Ссылка на другой пакет - неопределенный символ - PullRequest
0 голосов
/ 18 мая 2018

Я пытаюсь использовать классы c ++ из пакета rlas (на CRAN).Я написал следующее:

#include <Rcpp.h>
#include <rlasstreamer.h>

// [[Rcpp::depends(rlas)]]

using namespace Rcpp;

// [[Rcpp::export]]
void f(CharacterVector file)
{
  RLASstreamer lasstreamer(file);
  return;
}

Также я добавил LinkingTo: Rcpp,rlas в DESCRIPTION.Пакет компилируется, поэтому заголовок найден, но библиотека не связана:

undefined symbol: _ZN12RLASstreamerD1Ev

Команда связывания выглядит так, но ничего не связано с rlas

g++ -shared -L/usr/lib/R/lib -Wl,-Bsymbolic-functions -Wl,-z,relro -o pkgname.so function_f.o RcppExports.o -L/usr/lib/R/lib -lR

Как решениеЯ обманул, создав Makevars с жестко закодированным путем к библиотеке, который находится в моем home/.

PKG_LIBS= /home/user/R/x86_64-pc-linux-gnu-library/3.4/rlas/libs/rlas.so

И это работает!

Я верил, что это работаиз Rcpp::depends тегов.Что я пропустил, чтобы правильно связать другой пакет R?Может ли он быть из пакета rlas, который может быть плохо сформирован?

1 Ответ

0 голосов
/ 18 мая 2018

Вместо использования жестко закодированного пути в Makevars вы можете динамически создать подходящую запись в течение configure.Вот некоторый R-код, который можно использовать для поиска местоположения библиотеки:

libs.dir <- system.file( "libs", package = "rlas")
paste0(libs.dir, .Platform$file.sep, "rlas", .Platform$dynlib.ext)

Вы можете даже добавить это к rlas вместе с функцией rlas.package.skeleton.См., Например, мой пакет RcppArrayFire:

Редактировать: Вот обработанный пример:

Создайте скелет пакета, измените каталог

$ Rscript -e "Rcpp::Rcpp.package.skeleton()"
$ cd anRpackage

Создайте или обновите некоторые файлы:

$ cat configure
#!/bin/sh
RLAS_LIBS=`Rscript -e "cat(system.file('libs', 'rlas.so', package = 'rlas'))"`
sed -e "s|@RLAS_LIBS@|${RLAS_LIBS}|" src/Makevars.in > src/Makevars

$ cat cleanup
#!/bin/sh
rm -f src/Makevars src/*.o src/*.so

$ cat src/Makevars.in 
PKG_LIBS = @RLAS_LIBS@

$ cat src/rcpp_hello_world.cpp 
#include <Rcpp.h>
#include <rlasstreamer.h>

// [[Rcpp::export]]
void rcpp_hello_world() {
  RLASstreamer lasstreamer("foo");
  return;
}

$ grep rlas DESCRIPTION
LinkingTo: Rcpp, rlas

Скомпилируйте атрибуты Rcpp:

$ Rscript -e "Rcpp::compileAttributes()"

Сборка, проверкаи установите пакет:

$ R CMD build .
[...]
$ R CMD check anRpackage_1.0.tar.gz 
[...]
$ R CMD INSTALL anRpackage_1.0.tar.gz 
[...]
g++ -shared -L/usr/lib/R/lib -Wl,-z,relro -o anRpackage.so RcppExports.o rcpp_hello_world.o /usr/local/lib/R/site-library/rlas/libs/rlas.so -L/usr/lib/R/lib -lR
[...]

Здесь интересует командная строка из компоновщика.Это показывает, что rlas.so включено с полным путем.Теперь попробуйте пакет:

$ Rscript -e "anRpackage::rcpp_hello_world()"
ERROR: cannot open file 'foo'
ERROR: cannot open lasreadertxt with file name 'foo'
Fehler in anRpackage::rcpp_hello_world() : 
  LASlib internal error. See message above.
Execution halted

Итак, пока мы получаем ошибку, это ошибка от LASlib, которая содержится в rlas.so.Если мы посмотрим на вывод ldd, то снова увидим rlas.so, включенный с полным путем, который отличается от других связанных библиотек:

$ ldd ~/R/x86_64-pc-linux-gnu-library/3.5/anRpackage/libs/anRpackage.so
    linux-vdso.so.1 (0x00007ffe4c79d000)
    /usr/local/lib/R/site-library/rlas/libs/rlas.so (0x00007fede63fc000)
    libR.so => /usr/lib/libR.so (0x00007fede5d7a000)
    libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fede59f8000)
[...]
...