Использование сторонних заголовочных файлов с Rcpp
у меня есть файл заголовка под названием coolStuff.h
, который содержит функцию awesomeSauce(arg1)
что я хотел бы использовать в моем исходном файле cpp.
Каталог Структуру:
- RworkingDirectory
- sourceCpp
- theCppFile.cpp
- cppHeaders
- coolStuff.h
- sourceCpp
Код:
#include <Rcpp.h>
#include <cppHeaders/coolStuff.h>
using namespace Rcpp;
// [[Rcpp::export]]
double someFunctionCpp(double someInput){
double someOutput = awesomeSauce(someInput);
return someOutput;
}
я получаю ошибка:
theCppFile.cpp:2:31: error: cppHeaders/coolStuff.h: No such file or directory
я переместил файл и каталог повсюду и, похоже, не могу заставить это работать. Я вижу примеры по всему месту использования сторонних заголовков, которые говорят, что просто сделайте это:
#include <boost/array.hpp>
(это из Hadley/devtools)
https://github.com/hadley/devtools/wiki/Rcpp
так что это дает? Я искал все утро и не могу найти ответ на то, что мне кажется простым вещь.
обновление 01.11.12
теперь, когда я понял, как создавать пакеты, которые используют Rcpp в Rstudio, позвольте мне перефразировать вопрос. У меня есть автономный файл заголовка coolStuff.h, который содержит функцию, которую я хочу использовать в коде cpp.
1) где я должен разместить coolStuff.h в структуре каталогов пакета, поэтому функция, которую он содержит, может использоваться theCppFile.cpp?
2) Как мне вызвать coolStuff.h в файлах cpp? Спасибо снова за вашу помощь. Я многому научился из последнего разговора.
Примечание: я прочитал виньетку "написание пакета, который использует Rcpp", и она не объясняет, как это сделать.
Ответ:
OK позвольте мне резюмировать ответ на мой вопрос, так как он разбросан по этой странице. Если я получу деталь неправильно, не стесняйтесь редактировать это или дайте мне знать, и я отредактирую его:
Итак, вы нашли .h
или , который содержит функция или какой-либо другой бит кода, который вы хотите использовать в .cpp
файл, который вы пишете, чтобы использовать с Rcpp
.
давайте продолжать называть этот найденный код coolStuff.h
и вызвать функцию, которую вы хотите использовать awesomeSauce()
. Позволяет вызвать файл, который вы пишете theCppFile.cpp
.
(я должен отметить здесь, что код в .H-файлы и в .cpp-файлы - это весь код C++, и разница между ними заключается в том, что программист C++ держит вещи организованными надлежащим образом. Я оставлю обсуждение разница здесь, но простой поиск здесь на SO приведет вас к обсуждению разницы. Для вас R-программист должен использовать немного кода, который вы нашли, нет никакой реальной разницы.)
КОРОЧЕ: вы можете использовать файл как coolStuff.h
при условии, что он не вызывает никаких других библиотек, либо вырезать и вставить в theCppFile.cpp
, или если вы создаете пакет, вы можете поместить файл в С theCppFile.cpp
файл и использовать #include "coolStuff.h"
в верхней части файла ты пишешь. Последнее является более гибким и позволяет использовать функции coolStuff.h
в другой .cpp
файлы.
детали:
1) coolStuff.h
не следует вызывать другие библиотеки. Таким образом, это означает, что он не может иметь никаких операторов include вверху. Если это так, то, что я подробно расскажу ниже, вероятно, не сработает, и использование найденного кода, вызывающего другие библиотеки, выходит за рамки этого ответа.
2) Если вы хотите скомпилировать файл с sourceCpp()
нужно вырезать и вставить coolStuff.h
на theCppFile.cpp
. Мне говорили, что бывают исключения, но sourceCpp()
предназначен для компиляции одного .cpp
файл, так что это лучший маршрут.
(примечание: Я не гарантирую, что простой вырезать и вставить будет работать из коробки. Возможно, вам придется переименовать переменные или, скорее всего, переключить используемые типы данных в соответствии с используемыми в theCppFile.cpp
. Но до сих пор cut-and-paste работал с минимальной суетой для меня с 6 разные простые .h
файлы)
3) Если вам нужно использовать код coolStuff.h
на theCppFile.cpp
и нигде больше, тогда вы должны вырезать и вставить его в theCppFile.cpp
.
(опять же, я не даю никаких гарантий см. Примечание выше о вырезании и вставке)
4) Если вы хотите использовать код, содержащийся в coolStuff.h
на theCppFile.cpp
и другие .cpp
файлы, вам нужно изучить создание пакета. Это не сложно, но может быть немного сложно, потому что информация там о построение пакетов с Rcpp варьируется от исчерпывающей тщательной документации, которую вы хотите с любым пакетом R (но это выше вашей головы как новичка), и чувствительных введений новичка (которые могут оставить деталь вы случись нужда).
вот что я предлагаю:
A) сначала получите версию theCppFile.cpp
С кодом от coolStuff.h
вырезать-и-вставить в theCppFile.cpp
, что составляет с sourceCpp()
и работает, как вы ожидаете. Это не обязательно, но если вы новичок в Rcpp или пакетах, приятно убедиться, что ваш код работает в этой простой ситуации, прежде чем перейти к более сложному случаю ниже.
B) Теперь создайте свой пакет, используя Rcpp.package.skeleton()
или используйте функцию сборки в RStudio (настоятельно рекомендуется). Вы можете найти подробную информацию об использовании Rcpp.package.skeleton()
на Хэдли/инструменты разработчика или Виньетка Атрибутов Rcpp. Полная документация для написания пакетов с Rcpp находится в написание пакета что использует Rcpp, однако это предполагает, что вы знаете свой путь вокруг C++ довольно хорошо, и не использует новый способ "атрибуты" делать Rcpp.
не забудьте "построить и перезагрузить", если используете RStudio или compileAttributes()
если вы не в RStudio.
C) теперь вы должны увидеть в своем каталоге R файл с именем RcppExports.R
. Открой и проверь. В RcppExports.R
вы должны увидеть функции оболочки R для всех .cpp-файлы у вас в папке . Хорошенький сладкий.
D) попробуйте функцию R, соответствующую функции, которую вы написали в theCppFile.cpp
. Это работает? Если да, то двигайтесь дальше.
E) с вашим пакетом построен вы можете двигаться coolStuff.h
на С theCppFile.cpp
.
F) теперь вы можете удалить код вырезания и вставки из theCppFile.cpp
и в самом верху theCppFile.cpp
(и любых других .cpp-файл, который вы хотите использовать из coolStuff.з) поставить #include "coolStuff.h"
сразу после #include <Rcpp.h>
. Обратите внимание, что нет скобок вокруг рядовой.h, скорее есть"". Это c++ конвенции, включая локальные файлы, предоставленные пользователем, а не файл библиотеки, как Rcpp или STL и т. д...
G) Теперь вам нужно перестроить пакет. В RStudio это просто "Build & Reload" в меню сборки. Если вы не используете RStudio, вы должны запустить compileAttributes()
H) теперь попробуйте функцию R снова, как и на шаге D), надеюсь, она работает.
7 ответов
проблема в том, что sourceCpp
явно предназначен для создания только одного автономного исходного файла. Если вы хотите sourceCpp
чтобы иметь зависимости, они должны быть либо:
в систему входят каталоги (т. е.
/usr/local/lib
или/usr/lib
) илив пакете R, который вы перечисляете в
Rcpp::depends
атрибут
как сказал Дирк, если вы хотите создать более одного исходного файла, вы должны рассмотреть возможность использования R пакет, а не sourceCpp
.
обратите внимание, что если вы работаете над пакетом и выполняете sourceCpp для файла в каталоге src пакета, он построит его как будто это в пакете (т. е. вы можете включать файлы из каталога src или каталога inst/include).
я смог связать любую библиотеку (MPFR в этом случае), установив две переменные среды перед вызовом sourceCpp:
Sys.setenv("PKG_CXXFLAGS"="-I/usr/include")
Sys.setenv("PKG_LIBS"="-L/usr/lib/x86_64-linux-gnu/ -lm -lmpc -lgmp -lmpfr")
первая переменная содержит путь к заголовкам библиотеки. Второй включает в себя путь двоичного файла библиотеки и его имя файла. В этом случае также требуются другие зависимые библиотеки. Для получения более подробной информации проверьте компиляцию g++ и ссылку флаги. Эту информацию обычно можно получить, используя pkg-config:
pkg-config --cflags --libs mylib
для лучшего понимания я рекомендую использовать sourceCpp с подробным выводом для печати компиляции g++ и связывания команд:
sourceCpp("mysource.cpp", verbose=TRUE, rebuild=TRUE)
я смог связать библиотеку boost, используя следующую глобальную команду в R перед вызовом sourceCpp
Sys.setenv("PKG_CXXFLAGS"="-I \path-to-boost\")
в основном зеркальное отображение этого сообщения, но с другой опцией компилятора:http://gallery.rcpp.org/articles/first-steps-with-C++11/
пару вещей:
"сторонние библиотеки заголовков", как в вашей теме, не имеет смысла.
сторонние заголовки могут работать через шаблонный код, где заголовки-это все, что вам нужно, т. е. есть только шаг включения, и компилятор разрешает вещи.
Как только вам понадобятся библиотеки и фактическая привязка объектного кода, Вы не сможете использовать мощный и полезный
sourceCpp
Если вы не дали ему мета-информацию через плагины (или env. Вар.)в этом случае напишите пакет.
простые и простые вещи-это только то, что с Rcpp и новыми атрибутами или старыми встроенными и cxxfunction
. Больше для комплексного использования - - - и внешние библиотеки is более сложный вам нужно проконсультироваться с документацией. Для этого мы добавили несколько виньеток в Rcpp.
угловые скобки предназначены для системных включений, таких как стандартные библиотеки.
для файлов, локальных для вашего собственного проекта, используйте кавычки:"".
кроме того, если вы размещаете заголовки в другом каталоге, путь к заголовку должен быть указан локально для исходного файла, включая его.
Так что для вашего примера это должно работать:
#include "../cppHeaders/coolStuff.h"
вы можете настроить пути поиска так, чтобы файл можно было найти без этого, но это, как правило, только стоит сделать это для вещей, которые вы хотите включить в несколько проектов, или иначе ожидаете, что кто-то "установит".
мы можем добавить его, написав путь в заголовок PKG_CXXFLAGS
переменная .R/Makevars
файл, как показано ниже. Ниже приведен пример добавления файла заголовка xtensor
установлен с Anaconda в macOS.
⋊> ~ cat ~/.R/Makevars
CC=/usr/local/bin/gcc-7
CXX=/usr/local/bin/g++-7
CPLUS_INCLUDE_PATH=/opt/local/include:$CPLUS_INCLUDE_PATH
PKG_CXXFLAGS=-I/Users/kuroyanagi/.pyenv/versions/miniconda3-4.3.30/include
LD_LIBRARY_PATH=/opt/local/lib:$LD_LIBRARY_PATH
CXXFLAGS= -g0 -O3 -Wall
MAKE=make -j4
это работает для меня в Windows:
Sys.setenv("PKG_CXXFLAGS"='-I"C:/boost/boost_1_66_0"')
Edit: на самом деле вам это не нужно, если вы используете заголовки Boost (благодаря Ralf Stubner):
// [[Rcpp::depends(BH)]]