У меня есть файл заголовка coolStuff.h
которая содержит функцию awesomeSauce(arg1)
что я хотел бы использовать в моем исходном файле cpp.
Структура каталогов:
Код:
#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>
(Это от Хэдли / devtools)
https://github.com/hadley/devtools/wiki/Rcpp
Так что же дает? Я искал все утро и не могу найти ответ на то, что мне кажется простым делом.
Хорошо, теперь, когда я понял, как создавать пакеты, которые используют Rcpp в Rstudio, позвольте мне перефразировать вопрос. У меня есть отдельный заголовочный файл coolStuff.h, который содержит функцию, которую я хочу использовать в своем коде cpp.
1) Где я должен поместить файл coolStuff.h в структуру каталогов пакета, чтобы содержащаяся в нем функция могла использоваться в CppFile.cpp?
2) Как мне вызвать coolStuff.h в файлах cpp? В очередной раз благодарим за помощь. Я многому научился из последнего разговора.
Примечание: я прочитал виньетку «Написание пакета, использующего Rcpp», и он не объясняет, как это сделать.
Хорошо, позвольте мне обобщить ответ на мой вопрос, так как он разбросан по всей этой странице. Если я ошибаюсь в деталях, не стесняйтесь редактировать это или дайте мне знать, и я отредактирую это:
Итак, вы нашли .h
или же .cpp
файл, который содержит функцию или какой-то другой бит кода, который вы хотите использовать в .cpp
файл, который вы пишете для использования Rcpp
,
Давайте продолжать называть этот найденный код coolStuff.h
и вызвать функцию, которую вы хотите использовать awesomeSauce()
, Позволяет вызвать файл, который вы пишете theCppFile.cpp
,
(Здесь я должен отметить, что код в файлах .h и в файлах .cpp — это весь код C ++, и разница между ними заключается в том, чтобы программист C ++ организовывал вещи должным образом. Я оставлю обсуждение различий здесь , но простой поиск здесь на SO приведет вас к обсуждению разницы. Для вас, программиста R, которому нужно использовать немного кода, который вы нашли, нет никакой реальной разницы.)
КОРОЧЕ: Вы можете использовать файл как coolStuff.h
при условии, что он не вызывает никаких других библиотек, либо вырезать и вставить в theCppFile.cpp
или, если вы создаете пакет, вы можете поместить файл в \src
каталог с theCppFile.cpp
файл и использование #include "coolStuff.h"
в верхней части файла, который вы пишете. Последний является более гибким и позволяет использовать функции в coolStuff.h
в других .cpp
файлы.
ПОДРОБНОСТИ:
1) coolStuff.h
не должны вызывать другие библиотеки. Таким образом, это означает, что в верхней части не может быть никаких операторов включения. Если это произойдет, то, что я подробно опишу ниже, вероятно, не будет работать, и использование найденного кода, который вызывает другие библиотеки, выходит за рамки этого ответа.
2) Если вы хотите скомпилировать файл с sourceCpp()
вам нужно вырезать и вставлять coolStuff.h
в theCppFile.cpp
, Мне говорят, что есть исключения, но sourceCpp()
предназначен для компиляции одного .cpp
файл, так что это лучший путь.
(ПРИМЕЧАНИЕ. Я не даю никаких гарантий, что простое вырезание и вставка будут работать из коробки. Возможно, вам придется переименовать переменные или, скорее, переключить используемые типы данных, чтобы они соответствовали тем, которые вы используете в theCppFile.cpp
, Но до сих пор, вырезать и вставить работал с минимальной суетой для меня с 6 различными простыми .h
файлы)
3) Если вам нужно только использовать код из coolStuff.h
в theCppFile.cpp
и больше нигде, тогда вы должны вырезать и вставить его в theCppFile.cpp
,
(Опять же, я не даю никаких гарантий, см. Примечание выше о вырезке и вставке)
4) Если вы хотите использовать код, содержащийся в coolStuff.h
в theCppFile.cpp
И другие .cpp
файлы, вы должны посмотреть на создание пакета. Это не сложно, но может быть немного сложно, потому что информация о сборке пакетов с помощью Rcpp варьируется от исчерпывающей исчерпывающей документации, которую вы хотите получить с любым пакетом R (но это выше вашего понимания как новичок), и новичка, чувствительного к этому. введения (которые могут опустить детали вы случиться нужно).
Вот что я предлагаю:
А) Сначала получите версию theCppFile.cpp
с кодом из coolStuff.h
вырезать и вставлять в theCppFile.cpp
который компилируется с sourceCpp()
и работает так, как вы ожидаете. Это не обязательно, но если вы новичок в пакетах Rcpp OR, неплохо убедиться, что ваш код работает в этой простой ситуации, прежде чем переходить к более сложному случаю ниже.
B) Теперь создайте свой пакет, используя Rcpp.package.skeleton()
или используйте функциональность Build в RStudio (НАСТОЯТЕЛЬНО рекомендуется). Вы можете найти подробную информацию об использовании Rcpp.package.skeleton()
в Hadley / DevTools или же Rcpp атрибуты виньетка. Полная документация для написания пакетов с Rcpp находится в Написание пакета, который использует Rcpp, однако этот предполагает, что вы достаточно хорошо разбираетесь в C ++, и не использует новый способ «Атрибутов» для выполнения Rcpp.
Не забудьте «построить» & Обновить «, если используется RStudio или compileAttributes()
если вы не в RStudio.
C) Теперь вы должны увидеть в вашем каталоге \ R файл с именем RcppExports.R
, Откройте это и проверьте это. В RcppExports.R
Вы должны увидеть функции оболочки R для всех файлов .cpp, которые есть в вашем \src
каталог. Довольно мило.
D) Попробуйте функцию R, которая соответствует функции, которую вы написали в theCppFile.cpp
, Это работает? Если так, то иди дальше.
E) С вашим пакетом вы можете двигаться coolStuff.h
в src
папка с theCppFile.cpp
,
F) Теперь вы можете удалить код вырезания и вставки из theCppFile.cpp
и на вершине theCppFile.cpp
(и любой другой файл .cpp, в котором вы хотите использовать код из coolStuff.h) #include "coolStuff.h"
сразу после #include <Rcpp.h>
, Обратите внимание, что вокруг ranker.h нет скобок, скорее есть «». Это соглашение C ++ при включении локальных файлов, предоставляемых пользователем, а не файла библиотеки, такого как Rcpp или STL и т. Д.
G) Теперь вам нужно пересобрать пакет. В RStudio это просто «Build & Перезагрузить »в меню Build. Если вы не используете RStudio, вы должны запустить compileAttributes()
H) Теперь попробуйте снова функцию R, как вы делали на шаге D), надеюсь, она сработает.
Проблема в том, что 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)
Я смог связать библиотеку наддува с помощью следующей глобальной команды в R перед вызовом sourceCpp
Sys.setenv("PKG_CXXFLAGS"="-I \path-to-boost\")
В основном зеркальное отражение этого поста, но с другой опцией компилятора: http://gallery.rcpp.org/articles/first-steps-with-C++11/
Пара вещей:
«Сторонние библиотеки заголовков» как в вашей теме не имеют смысла.
Сторонние заголовки могут работать через шаблонный код, где заголовки — это все, что вам нужно, то есть есть только шаг включения, и компилятор решает проблемы.
Если вам нужны библиотеки и фактическое связывание объектного кода, вы не сможете получить мощную и полезную sourceCpp
если вы не предоставили ему мета-информацию через плагины (или env. vars).
Так что в этом случае напишите пакет.
Легкие и простые вещи — это то же самое, что с Rcpp и новыми атрибутами, или старыми встроенными и cxxfunction
, Больше для комплексного использования — и внешние библиотеки является Более сложный, вам нужно ознакомиться с документацией. Для этого мы добавили несколько виньеток в 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"')
Изменить: На самом деле вам это не нужно, если вы используете Boost Headers (спасибо Ральфу Стубнеру):
// [[Rcpp::depends(BH)]]