Я написал источник cpp с включенным заголовочным файлом pari.h:
#include<string>
#include<vector>
#include<algorithm>
#include<cmath>
#include<stdlib.h>
#include<time.h>
#include<iterator> // for ostream_iterator
#include<strings.h>
#include<string.h>
#include<sstream>
#include <pari/pari.h> // for PARI/GP library
#include<Rcpp.h> // for sourceCpp to work, this line must be uncommented
// Enable C++11 via this plugin (Rcpp 0.10.3 or later)
// [[Rcpp::plugins(cpp11)]]
using namespace std;
using namespace Rcpp; // for sourceCpp to work, this line must be uncommented
// [[Rcpp::export]]
int main() {
long maxp = 1000000; // max value
pari_init(500000,2); // initiate pari
size_t rsize = 500000; // set stack size variables
size_t vsize = 100000000;
void paristack_setsize(size_t rsize, size_t vsize); // declare stack function
paristack_setsize(rsize, vsize); // set stack size
gp_allocatemem(stoi(100000000)); // allocate memory
GEN p1; // declare PARI variable
p1 = cgetg(maxp, t_VEC); // make the PARI variable a vector
long j; // declare the variable for the number to be checked. one above the vector iterator
for (long i = 0; i <= maxp; ++i) { // iterate over PARI vector
j = i + 1; // decrement index for number
gel(p1, i) = sumdiv(stoi(j)); // calculate the sum of divisors and update the vector
}
vector<long> p2(maxp); // empty vector of native type
GEN x; // declare a PARI variable to subset PARI vector
for (long i = 0; i < maxp; i++) { // for2, across vector indices
x = gel(p1, i); // subset one item of vector
p2[i] = gtolong(x); // convert PARI to native long integer and update long vector item
} // close for2
for (long z = 0; z < maxp; z++) { // for3, to iterate for stdout
cout << p2[z] << '\n'; // return the result. the vector items are printed separately
} // close for3
} // close function
(Обратите внимание, что могут быть ненужные заголовки, я обычно копирую их все из источников, но это не проблема). Подобные исходные файлы без заголовка pari.h хорошо компилируются с Rcpp с включенными необходимыми частями (такими как заголовок, пространство имен, строка экспорта и т. Д.).
Источник, когда ссылки, связанные с Rcpp, прокомментированы, хорошо компилируется и работает без проблем при компиляции напрямую с g ++ со следующими флагами:
g++ -lpari -fpermissive -Wall -Wextra -lm -fno-strict-aliasing -fomit-frame-pointer -o sumdivisors.o sumdivisors.cpp
Я также импортировал эти флаги в R:
Sys.setenv("PKG_CXXFLAGS"="-lpari -fpermissive -Wall -Wextra -lm -fno-strict-aliasing -fomit-frame-pointer")
Я также создал символическую ссылку в /usr/local/lib64/R/library/Rcpp/include/
на каталог pari в /usr/include
.
Однако вывод команды sourceCpp выглядит так:
> sourceCpp("sumdivisors.cpp")
In file included from /usr/local/lib64/R/library/Rcpp/include/Rcpp/r/headers.h:48:0,
from /usr/local/lib64/R/library/Rcpp/include/RcppCommon.h:29,
from /usr/local/lib64/R/library/Rcpp/include/Rcpp.h:27,
from sumdivisors.cpp:15:
/usr/local/lib64/R/library/Rcpp/include/Rcpp/platform/compiler.h:47:0: warning: "GCC_VERSION" redefined
#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
In file included from /usr/local/lib64/R/library/Rcpp/include/pari/pari.h:16:0,
from sumdivisors.cpp:14:
/usr/local/lib64/R/library/Rcpp/include/pari/paricfg.h:19:0: note: this is the location of the previous definition
#define GCC_VERSION "gcc version 6.2.1 20160830 (GCC)"
Error in dyn.load("/tmp/Rtmpc9edZe/sourceCpp-x86_64-pc-linux-gnu-0.12.8/sourcecpp_188e46b44088/sourceCpp_2.so") :
unable to load shared object '/tmp/Rtmpc9edZe/sourceCpp-x86_64-pc-linux-gnu-0.12.8/sourcecpp_188e46b44088/sourceCpp_2.so':
/tmp/Rtmpc9edZe/sourceCpp-x86_64-pc-linux-gnu-0.12.8/sourcecpp_188e46b44088/sourceCpp_2.so: undefined symbol: pari_mainstack
Я повторил шаги с включением строки включения C ++ 11 или без нее, ничего не изменилось. Я также меняю флаги gcc, но безрезультатно. Похоже, что есть проблема с определением версии gcc и определением pari_mainstack.
Я считаю, что проблема не в том, как написан источник. Ниже приведены два примера, в которых приведенный выше код cpp преобразуется в код, возвращающий вектор, а функция не является основной. Также представлен аналогичный и простой код, который хорошо компилируется с Rcpp:
#include<stdio.h>
#include<numeric> // for "accumulate"
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
#include<cmath>
#include<stdlib.h>
#include<time.h>
#include<iterator> // for ostream_iterator
#include<strings.h>
#include<string.h>
#include<sstream>
#include <pari/pari.h> // for PARI/GP library
#include<Rcpp.h> // for sourceCpp to work, this line must be uncommented
// Enable C++11 via this plugin (Rcpp 0.10.3 or later)
// [[Rcpp::plugins(cpp11)]]
using namespace std;
using namespace Rcpp; // for sourceCpp to work, this line must be uncommented
// [[Rcpp::export]]
vector<long> sumdivisors() {
long maxp = 1000000; // max value
pari_init(500000,2); // initiate pari
size_t rsize = 500000; // set stack size variables
size_t vsize = 100000000;
void paristack_setsize(size_t rsize, size_t vsize); // declare stack function
paristack_setsize(rsize, vsize); // set stack size
gp_allocatemem(stoi(100000000)); // allocate memory
GEN p1; // declare PARI variable
p1 = cgetg(maxp, t_VEC); // make the PARI variable a vector
long j; // declare the variable for the number to be checked. one above the vector iterator
for (long i = 0; i <= maxp; ++i) { // iterate over PARI vector
j = i + 1; // decrement index for number
gel(p1, i) = sumdiv(stoi(j)); // calculate the sum of divisors and update the vector
}
vector<long> p2(maxp); // empty vector of native type
GEN x; // declare a PARI variable to subset PARI vector
for (long i = 0; i < maxp; i++) { // for2, across vector indices
x = gel(p1, i); // subset one item of vector
p2[i] = gtolong(x); // convert PARI to native long integer and update long vector item
} // close for2
return(p2);
/*
for (long z = 0; z < maxp; z++) { // for3, to iterate for stdout
cout << p2[z] << '\n'; // return the result. the vector items are printed separately
} // close for3
*/
} // close function
.
#include<stdio.h>
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
#include<cmath>
#include<math.h>
#include<time.h>
#include<Rcpp.h>
using namespace std;
using namespace Rcpp;
//#include "std_lib_facilities.h"
// [[Rcpp::export]]
int pe001Cpp(int x) { // define a function pe001 with one in$teger input
int sum35 = 0; // define a scalar for the sum. start value is 0
for (int i=1; i<x; ++i) { // for 1 loop for counting up to x
if (i % 3 == 0 || i % 5 == 0) { // if 1, divisible by 3 or 5
sum35 += i; // update sum
} // close if 1
} // close for 1
return sum35; // return the final value
} // close function
// [[Rcpp::export]]
int pe001Cppb(int x) { // efficient method
int sumdivisible(int x, int y); // declare the below function in this scope
return sumdivisible(x, 3) + sumdivisible(x, 5) - sumdivisible(x, 15); // return the total sum
} // close function pe001Cppb
int sumdivisible(int x, int y) { // sum of terms divisibile by y
int ny = floor ((x-1) / y); // number of terms less than x and divisible by y
return ny * (ny + 1) / 2 * y; // return the sum
} // close function sumdivisible
Отфильтрованный вывод strace при выполнении напрямую скомпилированного двоичного файла выглядит следующим образом:
open("/usr/lib/libpari-gmp-tls.so.5", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libstdc++.so.6", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libm.so.6", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libgmp.so.10", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libnss_compat.so.2", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libnsl.so.1", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libnss_nis.so.2", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libnss_files.so.2", O_RDONLY|O_CLOEXEC) = 3
Как мы видим отсюда, https://github.com/rstats-db/RPostgres/issues/80, проблема может заключаться в неправильной версии связанной библиотеки, которую можно решить с помощью символьной ссылки. Поэтому мне нужно знать, с какими файлами библиотеки Rcpp пытается связать.
Обновлять:
Вывод Scanelf показывает, что проблемный символ находится в /usr/lib/libpari-gmp-tls.so.2.9.1.
[s@SS ~]$ scanelf -l -s pari_mainstack | grep pari_mainstack
ET_DYN pari_mainstack /usr/lib/libpari-gmp-tls.so.2.9.1
Вывод strace скомпилированного файла g ++ показывает, что исполняемый файл связан с /usr/lib/libpari-gmp-tls.so.5, который сам является символической ссылкой на версию 2.9.1:
[s@SS library]$ strace ./sumdivisors3.o |& grep so | grep -v "No such file"
execve("./sumdivisors3.o", ["./sumdivisors3.o"], [/* 79 vars */]) = 0
open("/usr/lib/libpari-gmp-tls.so.5", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libstdc++.so.6", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libm.so.6", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libgmp.so.10", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3
socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 3
socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 3
open("/usr/lib/libnss_compat.so.2", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libnsl.so.1", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libnss_nis.so.2", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libnss_files.so.2", O_RDONLY|O_CLOEXEC) = 3
Вывод ldd из файла sourceCpp_4.so, созданного командой sourceCpp, выглядит следующим образом:
[s@SS library]$ ldd /tmp/Rtmpau9YqY/sourceCpp-x86_64-pc-linux-gnu-0.12.8/sourcecpp_3a105ad2bdba/sourceCpp_4.so
linux-vdso.so.1 (0x00007ffc28f9d000)
libR.so => not found
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x00007f5077111000)
libm.so.6 => /usr/lib/libm.so.6 (0x00007f5076e0d000)
libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x00007f5076bf6000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007f5076858000)
/usr/lib64/ld-linux-x86-64.so.2 (0x0000564489276000)
Я отслеживал все эти файлы с помощью ldd, и нет ссылки на библиотеки /usr/lib/libpari-gmp-tls.so.2.9.1 или /usr/lib/libpari-gmp-tls.so.5. Итак, вопрос в том, почему sourceCpp не может ссылаться на эти файлы с учетом необходимых заголовков (а g ++ может)?
Обновлять:
Подробный вывод sourceCpp показывает следующую команду:
g++ -I/usr/local/lib64/R/include -DNDEBUG -I/usr/local/include -I"/usr/local/lib64/R/library/Rcpp/include" -I"/home/s/codes/cpp/projecteuler/library" -lpari -fpic -g -O2 -c sumdivisors2.cpp -o sumdivisors2.o
g++ -shared -L/usr/local/lib64/R/lib -L/usr/local/lib64 -o sourceCpp_5.so sumdivisors2.o -L/usr/local/lib64/R/lib -lR
Я устанавливаю флаги с помощью (на самом деле -lpari достаточно:
Sys.setenv("PKG_CXXFLAGS"="-lpari")
Согласно выводам gp2c, флаг -lpari также должен быть включен на этапе связывания, но здесь его нет в команде связывания. Может ли это быть источником проблемы? Или до этого почему файл sourceCpp_5.so не связан с необходимой библиотекой pari?
И финал:
Зависимые библиотеки для связывания также должны быть явно объявлены через:
Sys.setenv ("PKG_LIBS" = "- lm -lpari -lc")
Флаги библиотеки задаются выводом gp2c. Кстати, чтобы решить проблему с версией gcc, вместо создания символической ссылки на исходный каталог заголовков pari я создал копию внутри пути библиотеки R и закомментировал строку:
// # определение GCC_VERSION "gcc version 6.2.1 20160830 (GCC)"
Теперь компиляция прошла успешно, R может наслаждаться скоростью PARI / GP в теоретико-числовых вычислениях в R благодаря Rcpp!
undefined symbol: pari_mainstack
? Правильный? - person coatless   schedule 13.01.2017int main()
, указывает на то, что вы не знаете некоторых идиом. Поэтому я поддерживаю свое предыдущее замечание, что это не ошибка Rcpp, а проблема пользователя, которую не следует публиковать в официальной системе отслеживания ошибок. - person coatless   schedule 13.01.2017sourceCpp()
, прямое встраиваниеpari
с заголовками Rcpp, наличиеint main()
, установлены неверные флаги и - основной виновник - R и pari не согласны по компиляторам). Если два фрагмента кода только что добавлены к вашему вопросу работают, то я не понимаю, в чем проблема, потому чтоvector<long> sumdivisors()
- это буквально предыдущий фрагмент кода sinint main()
. Подчеркните, что именно проблематично в вашем вопросе. Я буду бодрствовать следующие 30 минут. - person coatless   schedule 13.01.2017sourceCpp
. После того, как вы поместите это в пакет, вы должны связать с pari, используяPKG_LIBS
вsrc/Makevars
вместоPKG_CXXFLAGS
. Флаги компоновщика входят вPKG_LIBS
. - person jtilly   schedule 13.01.2017