Cppソースファイルで使用したい関数awesomeSauce(arg1)
を含むcoolStuff.h
というヘッダーファイルがあります。
ディレクトリ構造:
コード:
#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
では、何が得られるのでしょうか?私は午前中ずっと検索していて、単純なことのように思えるものに対する答えを見つけることができません。
RstudioでRcppを使用するパッケージを構築する方法がわかったので、質問を言い換えます。 cppコードで使用したい関数を含むスタンドアロンのヘッダーファイルcoolStuff.hがあります。
1)coolStuff.hをパッケージディレクトリ構造のどこに配置すれば、そこに含まれる関数をCppFile.cppで使用できるようになりますか?
2)cppファイルでcoolStuff.hを呼び出すにはどうすればよいですか?よろしくお願いします。前回の会話から多くのことを学びました。
注:「Rcppを使用するパッケージの作成」というビネットを読みましたが、その方法については説明されていません。
このページに散らばっているので、私の質問に対する答えを要約しましょう。詳細が間違っている場合は、これを編集するか、私に知らせてください。編集します:
そのため、Rcpp
で使用するために作成している.h
ファイルで使用する関数またはその他のコードを含む.cpp
または.cpp
ファイルが見つかりました。
この見つかったコードをcoolStuff.h
と呼び続け、使用したい関数をawesomeSauce()
と呼びましょう。あなたが書いているファイルをtheCppFile.cpp
と呼びましょう。
(ここで、.hファイルと.cppファイルのコードはすべてC++コードであり、それらの違いは、C++プログラマーが適切な方法で整理されていることです。違いについてはここで説明します。 、ただし、ここでSOを検索すると、違いについて説明できます。見つけたコードを少し使用する必要があるRプログラマーにとって、実際の違いはありません。)
IN SHORT:coolStuff.h
にカットアンドペーストするか、または作成した場合、他のライブラリを呼び出さない限り、theCppFile.cpp
のようなファイルを使用できます。パッケージでは、ファイルを\src
ファイルとともにtheCppFile.cpp
ディレクトリに配置し、書き込んでいるファイルの先頭で#include "coolStuff.h"
を使用できます。後者はより柔軟性があり、他のcoolStuff.h
ファイルの.cpp
の関数を使用できます。
詳細:
1)coolStuff.h
は他のライブラリを呼び出さないでください。つまり、上部にincludeステートメントを含めることはできません。もしそうなら、私が以下に詳述することはおそらく機能しないでしょう、そして他のライブラリを呼び出す見つかったコードの使用はこの答えの範囲を超えています。
2)sourceCpp()
を使用してファイルをコンパイルする場合は、coolStuff.h
を切り取ってtheCppFile.cpp
に貼り付ける必要があります。例外があると言われていますが、sourceCpp()
は1つの.cpp
ファイルをコンパイルするように設計されているため、これが最適なルートです。
(注:単純なカットアンドペーストがすぐに機能することを保証するものではありません。変数の名前を変更するか、使用しているデータ型をtheCppFile.cpp
で使用しているデータ型と一致させるように切り替える必要があります。しかしこれまでのところ、カットアンドペーストは、6つの異なる単純な.h
ファイルで最小限の手間で機能しました)
3)coolStuff.h
のtheCppFile.cpp
のコードのみを使用する必要があり、他の場所では使用する必要がない場合は、それを切り取ってtheCppFile.cpp
に貼り付ける必要があります。
(繰り返しますが、カットアンドペーストに関する上記の注を参照してください)
4)coolStuff.h
およびその他のtheCppFile.cpp
ファイルの.cpp
に含まれるコードを使用する場合は、パッケージの構築を検討する必要があります。これは難しいことではありませんが、Rcppを使用したパッケージの構築に関する情報は、Rパッケージで必要な徹底的なドキュメント(ただし、初心者としては頭上にあります)から、初心者に敏感なものまでさまざまであるため、少し注意が必要です。紹介(詳細が省略されている可能性がありますあなたがたまたま必要とします)。
これが私が提案するものです:
A)まず、theCppFile.cpp
からcoolStuff.h
にカットアンドペーストして、sourceCpp()
でコンパイルし、期待どおりに機能するコードを含むtheCppFile.cpp
のバージョンを取得します。これは必須ではありませんが、Rcpp ORパッケージを初めて使用する場合は、以下のより複雑なケースに進む前に、コードがこの単純な状況で機能することを確認してください。
B)Rcpp.package.skeleton()
を使用してパッケージをビルドするか、RStudioのビルド機能を使用します(強くお勧めします)。 Rcpp.package.skeleton()
の使用に関する詳細は、 hadley/devtools または Rcpp attributes Vignette にあります。 Rcppを使用してパッケージを作成するための完全なドキュメントは Rcppを使用するパッケージの作成 にありますが、これはC++の使い方をかなりよく知っていることを前提としており、新しい「属性」の方法を使用していません。 Rcpp。
RStudioを使用している場合は「ビルドとリロード」を、RStudioを使用していない場合はcompileAttributes()
を忘れないでください。
C)これで、\ RディレクトリにRcppExports.R
というファイルが表示されます。それを開いてチェックしてください。 RcppExports.R
には、\src
ディレクトリにあるすべての.cppファイルのRラッパー関数が表示されます。かなり甘い。
D)theCppFile.cpp
で書いた関数に対応するR関数を試してみてください。それは機能しますか?もしそうなら、次に進みます。
E)パッケージをビルドしたら、coolStuff.h
をtheCppFile.cpp
とともにsrc
フォルダーに移動できます。
F)これで、カットアンドペーストコードをtheCppFile.cpp
から削除し、theCppFile.cpp
(およびcoolStuff.hのコードを使用するその他の.cppファイル)の先頭に#include "coolStuff.h"
の直後に#include <Rcpp.h>
を配置できます。 ranker.hの前後には角かっこがなく、「」があることに注意してください。これは、RcppやSTLなどのライブラリファイルではなく、ユーザーが提供するローカルファイルを含める場合のC++規則です。
G)パッケージを再構築する必要があります。 RStudioでは、これは[ビルド]メニューの[ビルドとリロード]です。 RStudioを使用していない場合は、compileAttributes()
を実行する必要があります
H)ステップD)で行ったのと同じように、R関数を再試行します。うまくいけばうまくいきます。
問題は、sourceCpp
が単一のスタンドアロンソースファイルのみをビルドするように明示的に設計されていることです。 sourceCpp
に依存関係を持たせたい場合は、次のいずれかである必要があります。
システムにディレクトリを含めます(つまり、/usr/local/lib
または/usr/lib
)。または
Rcpp::depends
属性にリストするRパッケージ内
Dirkが言ったように、複数のソースファイルをビルドしたい場合は、sourceCpp
ではなくRパッケージの使用を検討する必要があります。
パッケージで作業していて、パッケージのsrcディレクトリ内のファイルに対してsourceCppを実行すると、パッケージがビルドされることに注意してくださいあたかもパッケージ内にあります(つまり、srcディレクトリのファイルを含めることができます)またはinst/includeディレクトリ)。
SourceCppを呼び出す前に、2つの環境変数を設定することで、任意のライブラリ(この場合はMPFR)をリンクできました。
Sys.setenv("PKG_CXXFLAGS"="-I/usr/include")
Sys.setenv("PKG_LIBS"="-L/usr/lib/x86_64-linux-gnu/ -lm -lmpc -lgmp -lmpfr")
最初の変数には、ライブラリヘッダーのパスが含まれています。 2つ目は、ライブラリバイナリのパスとそのファイル名を含みます。この場合、他の依存ライブラリも必要です。詳細については、g ++のコンパイルとリンクを確認してください flags 。この情報は通常、pkg-configを使用して取得できます。
pkg-config --cflags --libs mylib
理解を深めるために、g ++コンパイルおよびリンクコマンドを出力するために、詳細な出力でsourceCppを使用することをお勧めします。
sourceCpp("mysource.cpp", verbose=TRUE, rebuild=TRUE)
SourceCppを呼び出す前に、Rで次のグローバルコマンドを使用してブーストライブラリをリンクすることができました
Sys.setenv("PKG_CXXFLAGS"="-I \path-to-boost\")
基本的にこの投稿をミラーリングしますが、コンパイラオプションが異なります: http://gallery.rcpp.org/articles/first-steps-with-C++11/
いくつかのこと:
あなたの主題のような「サードパーティのヘッダーライブラリ」は意味がありません。
サードパーティのヘッダーは、ヘッダーだけが必要なテンプレートコードを介して機能します。つまり、インクルードステップのみがあり、コンパイラーが問題を解決します。
ライブラリとオブジェクトコードの実際のリンクが必要になると、プラグイン(またはenv。vars)を介してメタ情報を提供しない限り、強力で便利なsourceCpp
を使用できない場合があります。
その場合は、パッケージを作成してください。
簡単で単純なことは、Rcppと新しい属性、または古いインラインとcxxfunction
を使用した場合です。より複雑な使用---および外部ライブラリisより複雑な場合は、ドキュメントを参照する必要があります。そのために、Rcppにいくつかのビネットを追加しました。
山かっこ<>は、標準ライブラリなどのシステムインクルード用です。
独自のプロジェクトにローカルなファイルの場合は、引用符「」を使用します。
また、ヘッダーを別のディレクトリに配置する場合は、ヘッダーパスをそれを含むソースファイルに対してローカルに指定する必要があります。
したがって、あなたの例では、これは機能するはずです:
#include "../cppHeaders/coolStuff.h"
それを行わなくてもファイルが見つかるように検索パスを構成できますが、通常は、複数のプロジェクトに含めたいもの、または誰かが「インストール」することを期待するものに対してのみ行う価値があります。
以下に示すように、PKG_CXXFLAGS
ファイルの.R/Makevars
変数のヘッダーにパスを書き込むことで追加できます。以下は、macOSにAnacondaとともにインストールされたxtensor
のヘッダーファイルを追加する例です。
⋊> ~ 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"')
編集:ブーストヘッダーを使用する場合、実際にはこれは必要ありません(Ralf Stubnerのおかげで):
// [[Rcpp::depends(BH)]]