[Rcpp-commits] r3921 - in pkg/Rcpp: . R man src
noreply at r-forge.r-project.org
noreply at r-forge.r-project.org
Thu Nov 8 17:20:46 CET 2012
Author: jjallaire
Date: 2012-11-08 17:20:45 +0100 (Thu, 08 Nov 2012)
New Revision: 3921
Modified:
pkg/Rcpp/ChangeLog
pkg/Rcpp/R/Attributes.R
pkg/Rcpp/man/cppFunction.Rd
pkg/Rcpp/man/evalCpp.Rd
pkg/Rcpp/man/exportAttribute.Rd
pkg/Rcpp/man/interfacesAttribute.Rd
pkg/Rcpp/man/sourceCpp.Rd
pkg/Rcpp/src/Attributes.cpp
Log:
use .h suffix; handle package/src files specially; update documentation
Modified: pkg/Rcpp/ChangeLog
===================================================================
--- pkg/Rcpp/ChangeLog 2012-11-08 12:38:47 UTC (rev 3920)
+++ pkg/Rcpp/ChangeLog 2012-11-08 16:20:45 UTC (rev 3921)
@@ -1,9 +1,18 @@
2012-11-08 JJ Allaire <jj at rstudio.org>
+ * R/Attributes.R: special sourceCpp handling for file within the src
+ directory of a package; use .h as suffix for generated headers
* src/Attributes.cpp: add information on arguments to Rcpp module;
- use inline rather than static linkage for generated C++ shims
+ use inline rather than static linkage for generated C++ shims;
+ generated headers: add header guard and use .h suffix;
+ * man/cppFunction.Rd: update documentation
+ * man/sourceCpp.Rd: update documentation
+ * man/evalCpp.Rd: update documentation
+ * man/exportAttribute.Rd: update documentation
+ * man/interfacesAttribute.Rd: update documentation
+
2012-11-08 Romain Francois <romain at r-enthusiasts.com>
* R/Module.R: Module functions taking no arguments don't get the ellipsis
Modified: pkg/Rcpp/R/Attributes.R
===================================================================
--- pkg/Rcpp/R/Attributes.R 2012-11-08 12:38:47 UTC (rev 3920)
+++ pkg/Rcpp/R/Attributes.R 2012-11-08 16:20:45 UTC (rev 3921)
@@ -56,7 +56,7 @@
.validatePackages(depends, context$cppSourceFilename)
# temporarily modify environment for the build
- envRestore <- .setupBuildEnvironment(depends)
+ envRestore <- .setupBuildEnvironment(depends, file)
# temporarily setwd to build directory
cwd <- getwd()
@@ -128,9 +128,12 @@
"force a rebuild)\n\n", sep="")
}
- # load the module
- dll <- dyn.load(context$dynlibPath)
- populate(Module(context$moduleName, PACKAGE = dll, mustStart = TRUE), env)
+ # load the module if we have exported functions (else there is no module)
+ if (length(context$exportedFunctions) > 0) {
+ dll <- dyn.load(context$dynlibPath)
+ populate(Module(context$moduleName, PACKAGE = dll, mustStart = TRUE),
+ env)
+ }
# return (invisibly) a list of exported functions
invisible(context$exportedFunctions)
@@ -197,16 +200,18 @@
}
# Evaluate a simple c++ expression
-evalCpp <- function( code,
- depends = character(),
- includes = character(),
- showOutput = verbose,
- verbose = getOption( "verbose" ) ){
+evalCpp <- function(code,
+ depends = character(),
+ includes = character(),
+ rebuild = FALSE,
+ showOutput = verbose,
+ verbose = getOption( "verbose" ) ){
code <- sprintf( "SEXP get_value(){ return wrap( %s ) ; }", code )
env <- new.env()
- cppFunction( code, depends = depends, includes = includes, env = env, showOutput = showOutput )
+ cppFunction(code, depends = depends, includes = includes, env = env,
+ rebuild = rebuild, showOutput = showOutput)
fun <- env[["get_value"]]
fun()
}
@@ -267,11 +272,14 @@
}
+# Add LinkingTo dependencies if the sourceFile is in a package
.getSourceCppDependencies <- function(depends, sourceFile) {
- # add package LinkingTo dependencies if the source file is in a package
- descFile <- file.path(dirname(sourceFile), "..", "DESCRIPTION")
- if (file.exists(descFile)) {
+ # If the source file is in a package then simulate it being built
+ # within the package by including it's LinkingTo dependencies,
+ # the src directory (.), and the inst/include directory
+ if (.isPackageSourceFile(sourceFile)) {
+ descFile <- file.path(dirname(sourceFile), "..", "DESCRIPTION")
DESCRIPTION <- read.dcf(descFile, all = TRUE)
linkingTo <- .parseLinkingTo(DESCRIPTION$LinkingTo)
unique(c(depends, linkingTo))
@@ -280,6 +288,12 @@
}
}
+
+# Check whether a source file is in a package
+.isPackageSourceFile <- function(sourceFile) {
+ file.exists(file.path(dirname(sourceFile), "..", "DESCRIPTION"))
+}
+
# Error if a package is not currently available
.validatePackages <- function(depends, sourceFilename) {
unavailable <- depends[!depends %in% .packages(all.available=TRUE)]
@@ -302,7 +316,7 @@
# Setup the build environment based on the specified dependencies. Returns an
# opaque object that can be passed to .restoreEnvironment to reverse whatever
# changes that were made
-.setupBuildEnvironment <- function(depends) {
+.setupBuildEnvironment <- function(depends, sourceFile) {
# discover dependencies
buildEnv <- list()
@@ -359,6 +373,16 @@
# set CLINK_CPPFLAGS based on the LinkingTo dependencies
buildEnv$CLINK_CPPFLAGS <- .buildClinkCppFlags(linkingToPackages)
+
+ # if the source file is in a package then add standard package
+ # include directories
+ if (.isPackageSourceFile(sourceFile)) {
+ srcDir <- dirname(sourceFile)
+ incDir <- file.path(dirname(sourceFile), "..", "inst", "include")
+ buildEnv$CLINK_CPPFLAGS <- paste(buildEnv$CLINK_CPPFLAGS,
+ paste0('-I"', c(srcDir, incDir), '"'),
+ collapse=" ")
+ }
# add cygwin message muffler
buildEnv$CYGWIN = "nodosfilewarning"
@@ -488,7 +512,7 @@
# otherwise check for standard Rcpp::interfaces generated include
else if (!pluginsOnly) {
pkgPath <- find.package(package, NULL, quiet=TRUE)
- pkgHeader <- paste(package, ".hpp", sep="")
+ pkgHeader <- paste(package, ".h", sep="")
pkgHeaderPath <- file.path(pkgPath, "include", pkgHeader)
if (file.exists(pkgHeaderPath)) {
pkgInclude <- paste("#include <", pkgHeader, ">", sep="")
Modified: pkg/Rcpp/man/cppFunction.Rd
===================================================================
--- pkg/Rcpp/man/cppFunction.Rd 2012-11-08 12:38:47 UTC (rev 3920)
+++ pkg/Rcpp/man/cppFunction.Rd 2012-11-08 16:20:45 UTC (rev 3921)
@@ -50,7 +50,7 @@
\seealso{
-\code{\link{sourceCpp}}
+\code{\link{sourceCpp}}, \code{\link{evalCpp}}
}
\examples{
\dontrun{
Modified: pkg/Rcpp/man/evalCpp.Rd
===================================================================
--- pkg/Rcpp/man/evalCpp.Rd 2012-11-08 12:38:47 UTC (rev 3920)
+++ pkg/Rcpp/man/evalCpp.Rd 2012-11-08 16:20:45 UTC (rev 3921)
@@ -1,15 +1,16 @@
\name{evalCpp}
\alias{evalCpp}
\title{
-Evaluate a C++ expression
+Evaluate a C++ Expression
}
\description{
Evaluates a C++ expression. This creates a C++ function using
-\code{\link{cppFunction}} and call it to get the result.
+\code{\link{cppFunction}} and calls it to get the result.
}
\usage{
evalCpp(code, depends = character(), includes = character(),
- showOutput = verbose, verbose = getOption("verbose") )
+ rebuild = FALSE, showOutput = verbose,
+ verbose = getOption("verbose"))
}
\arguments{
\item{code}{
@@ -21,6 +22,9 @@
\item{includes}{
see \code{\link{cppFunction}}
}
+ \item{rebuild}{
+see \code{\link{cppFunction}}
+}
\item{showOutput}{
see \code{\link{cppFunction}}
}
@@ -29,13 +33,13 @@
}
}
\note{
- The result type of the C++ expression must be compatible with wrap.
+ The result type of the C++ expression must be compatible with \code{Rcpp::wrap}.
}
\value{
The result of the evaluated C++ expression.
}
\seealso{
-\code{\link{sourceCpp}} and \code{\link{cppFunction}}
+\code{\link{sourceCpp}}, \code{\link{cppFunction}}
}
\examples{
\dontrun{
Modified: pkg/Rcpp/man/exportAttribute.Rd
===================================================================
--- pkg/Rcpp/man/exportAttribute.Rd 2012-11-08 12:38:47 UTC (rev 3920)
+++ pkg/Rcpp/man/exportAttribute.Rd 2012-11-08 16:20:45 UTC (rev 3921)
@@ -29,7 +29,7 @@
}
\seealso{
-\code{\link{sourceCpp}}, \code{\link{compileAttributes}}
+\code{\link{sourceCpp}} and \code{\link{compileAttributes}}
}
\examples{
Modified: pkg/Rcpp/man/interfacesAttribute.Rd
===================================================================
--- pkg/Rcpp/man/interfacesAttribute.Rd 2012-11-08 12:38:47 UTC (rev 3920)
+++ pkg/Rcpp/man/interfacesAttribute.Rd 2012-11-08 16:20:45 UTC (rev 3921)
@@ -22,7 +22,7 @@
When \code{cpp} bindings are requested code is generated as follows:
\enumerate{
- \item Bindings are generated into a header file located in the \code{inst/include} directory of the package using the naming convention \emph{PackageName.hpp}
+ \item Bindings are generated into a header file located in the \code{inst/include} directory of the package using the naming convention \emph{PackageName.h}
\item The generated header file allows calling the exported C++ functions without any linking dependency on the package (this is based on using the \code{R_RegisterCCallable} and \code{R_GetCCallable} functions).
\item The exported functions are defined within a C++ namespace that matches the name of the package.
}
@@ -31,7 +31,7 @@
\preformatted{
// [[Rcpp::depends(MyPackage)]]
- #include <MyPackage.hpp>
+ #include <MyPackage.h>
void foo() {
MyPackage::bar();
@@ -44,7 +44,7 @@
\note{
- If a file by the name of \emph{PackageName.hpp} that wasn't generated by \code{compileAttributes} already exists in in the \code{inst/include} directory then it will not be overwritten (rather, an error will occur).
+ If a file by the name of \emph{PackageName.h} that wasn't generated by \code{compileAttributes} already exists in in the \code{inst/include} directory then it will not be overwritten (rather, an error will occur).
A static naming scheme for generated header files is used to ensure consistent usage semantics for clients of exported \code{cpp} interfaces. Packages that wish to export more complex interfaces or additional C++ types are therefore typically better off not using this mechanism.
Modified: pkg/Rcpp/man/sourceCpp.Rd
===================================================================
--- pkg/Rcpp/man/sourceCpp.Rd 2012-11-08 12:38:47 UTC (rev 3920)
+++ pkg/Rcpp/man/sourceCpp.Rd 2012-11-08 16:20:45 UTC (rev 3921)
@@ -7,8 +7,9 @@
\code{sourceCpp} parses the specified C++ file or source code and looks for functions marked with the \code{\link[=exportAttribute]{Rcpp::export}} attribute. A shared library is then built and its exported functions are made available as R functions in the specified environment.
}
\usage{
-sourceCpp(file = "", code = NULL, env = globalenv(), rebuild = FALSE,
- showOutput = verbose, verbose = getOption("verbose"))
+sourceCpp(file = "", code = NULL, env = globalenv(),
+ rebuild = FALSE, showOutput = verbose,
+ verbose = getOption("verbose"))
}
%- maybe also 'usage' for other objects documented here.
\arguments{
@@ -36,17 +37,23 @@
Functions exported using \code{sourceCpp} must meet several conditions, including being defined in the global namespace and having return types that are compatible with \code{Rcpp::wrap} and parameter types that are compatible with \code{Rcpp::as}. See the \code{\link[=exportAttribute]{Rcpp::export}} documentation for more details.
- If the code has compilation dependencies on other packages (e.g. \pkg{Matrix}, \pkg{RcppArmadillo}) then an \code{\link[=dependsAttribute]{Rcpp::depends}} attribute should be added naming these dependencies. Note that if you are sourcing a C++ file from within the \code{src} directory of a package then the package's \code{LinkingTo} dependencies are automatically included in the compilation.
+ If the source file has compilation dependencies on other packages (e.g. \pkg{Matrix}, \pkg{RcppArmadillo}) then an \code{\link[=dependsAttribute]{Rcpp::depends}} attribute should be provided naming these dependencies.
- The \code{sourceCpp} function will not rebuild the shared library if the underlying code has not changed since the last compilation.
+ The \code{sourceCpp} function will not rebuild the shared library if the source file has not changed since the last compilation.
}
\value{
Returns (invisibly) a character vector with the names of the R functions that were sourced into the specified environment.
}
+\note{
+ The \code{sourceCpp} function is designed for compiling a standalone source file whose only dependencies are R packages. If you are compiling more than one source file or have external dependencies then you should create an R package rather than using \code{sourceCpp}. Note that the \code{\link[=exportAttribute]{Rcpp::export}} attribute can also be used within packages via the \code{\link{compileAttributes}} function.
+
+ If you are sourcing a C++ file from within the \code{src} directory of a package then the package's \code{LinkingTo} dependencies, \code{inst/include}, and \code{src} directories are automatically included in the compilation.
+}
+
\seealso{
-\code{\link[=exportAttribute]{Rcpp::export}}, \code{\link[=dependsAttribute]{Rcpp::depends}}
+\code{\link[=exportAttribute]{Rcpp::export}}, \code{\link[=dependsAttribute]{Rcpp::depends}}, \code{\link{cppFunction}}, \code{\link{evalCpp}}
}
\examples{
Modified: pkg/Rcpp/src/Attributes.cpp
===================================================================
--- pkg/Rcpp/src/Attributes.cpp 2012-11-08 12:38:47 UTC (rev 3920)
+++ pkg/Rcpp/src/Attributes.cpp 2012-11-08 16:20:45 UTC (rev 3921)
@@ -384,7 +384,7 @@
}
virtual bool commit(const std::vector<std::string>& includes) {
-
+
// includes
std::ostringstream ostr;
if (!includes.empty()) {
@@ -440,7 +440,7 @@
const std::string& fileSep)
: ExportsGenerator(
packageDir + fileSep + "inst" + fileSep + "include" +
- fileSep + package + ".hpp",
+ fileSep + package + ".h",
package,
"//")
{
@@ -534,7 +534,9 @@
virtual void writeEnd() {
ostr() << "}" << std::endl;
- }
+ ostr() << std::endl;
+ ostr() << "#endif // " << getHeaderGuard() << std::endl;
+ }
virtual bool commit(const std::vector<std::string>& includes) {
@@ -545,6 +547,13 @@
// generate preamble
std::ostringstream ostr;
+
+ // header guard
+ std::string guard = getHeaderGuard();
+ ostr << "#ifndef " << guard << std::endl;
+ ostr << "#define " << guard << std::endl << std::endl;
+
+ // includes
if (!includes.empty()) {
for (std::size_t i=0;i<includes.size(); i++)
ostr << includes[i] << std::endl;
@@ -570,6 +579,10 @@
return ostr.str();
}
+ std::string getHeaderGuard() const {
+ return package() + "_RcppExports_h";
+ }
+
private:
std::string includeDir_;
bool hasCppInterface_;
@@ -867,11 +880,14 @@
SourceFileAttributes sourceAttributes(cppSourcePath_);
// generate RCPP module
- std::ostringstream ostr;
- ostr << "RCPP_MODULE(" << moduleName() << ") {" << std::endl;
- generateCppModuleFunctions(ostr, sourceAttributes, false);
- ostr << "}" << std::endl;
- generatedCpp_ = ostr.str();
+ generatedCpp_.clear();
+ if (!sourceAttributes.empty()) {
+ std::ostringstream ostr;
+ ostr << "RCPP_MODULE(" << moduleName() << ") {" << std::endl;
+ generateCppModuleFunctions(ostr, sourceAttributes, false);
+ ostr << "}" << std::endl;
+ generatedCpp_ = ostr.str();
+ }
// open source file and append module
std::ofstream cppOfs(generatedCppSourcePath().c_str(),
@@ -1052,6 +1068,7 @@
// return context as a list
Rcpp::List context;
+
context["moduleName"] = dynlib.moduleName();
context["cppSourcePath"] = dynlib.cppSourcePath();
context["buildRequired"] = buildRequired;
More information about the Rcpp-commits
mailing list