[Rcpp-commits] r4091 - pkg/Rcpp/src
noreply at r-forge.r-project.org
noreply at r-forge.r-project.org
Wed Dec 5 22:13:06 CET 2012
Author: jjallaire
Date: 2012-12-05 22:13:06 +0100 (Wed, 05 Dec 2012)
New Revision: 4091
Modified:
pkg/Rcpp/src/Attributes.cpp
pkg/Rcpp/src/AttributesGen.cpp
Log:
only append include Rcpp for sourceCpp
Modified: pkg/Rcpp/src/Attributes.cpp
===================================================================
--- pkg/Rcpp/src/Attributes.cpp 2012-12-05 20:49:04 UTC (rev 4090)
+++ pkg/Rcpp/src/Attributes.cpp 2012-12-05 21:13:06 UTC (rev 4091)
@@ -1,553 +1,556 @@
-// -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; indent-tabs-mode: nil; -*-
-//
-// Attributes.cpp: Rcpp R/C++ interface class library -- Rcpp attributes
-//
-// Copyright (C) 2012 JJ Allaire, Dirk Eddelbuettel and Romain Francois
-//
-// This file is part of Rcpp.
-//
-// Rcpp is free software: you can redistribute it and/or modify it
-// under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 2 of the License, or
-// (at your option) any later version.
-//
-// Rcpp is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Rcpp. If not, see <http://www.gnu.org/licenses/>.
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <errno.h>
-
-#include <fstream>
-#include <cstring>
-#include <map>
-#include <algorithm>
-
-#include <Rcpp.h>
-
-#include "AttributesGen.h"
-#include "AttributesParser.h"
-#include "AttributesUtil.h"
-
-// provide implementations for util
-namespace Rcpp {
-namespace attributes {
-
- // Utility class for getting file existence and last modified time
- FileInfo::FileInfo(const std::string& path)
- : path_(path), exists_(false), lastModified_(0)
- {
- #ifdef _WIN32
- struct _stat buffer;
- int result = _stat(path.c_str(), &buffer);
- #else
- struct stat buffer;
- int result = stat(path.c_str(), &buffer);
- #endif
- if (result != 0) {
- if (errno == ENOENT)
- exists_ = false;
- else
- throw Rcpp::file_io_error(errno, path);
- } else {
- exists_ = true;
- lastModified_ = buffer.st_mtime;
- }
- }
-
- // Remove a file (call back into R for this)
- bool removeFile(const std::string& path) {
- if (FileInfo(path).exists()) {
- Rcpp::Function rm = Rcpp::Environment::base_env()["file.remove"];
- rm(path);
- return true;
- }
- else {
- return false;
- }
- }
-
- // Recursively create a directory (call back into R for this)
- void createDirectory(const std::string& path) {
- if (!FileInfo(path).exists()) {
- Rcpp::Function mkdir = Rcpp::Environment::base_env()["dir.create"];
- mkdir(path, Rcpp::Named("recursive") = true);
- }
- }
-
- // Known whitespace chars
- const char * const kWhitespaceChars = " \f\n\r\t\v";
-
- // Query whether a character is whitespace
- bool isWhitespace(char ch) {
- return std::strchr(kWhitespaceChars, ch) != NULL;
- }
-
- // Trim a string
- void trimWhitespace(std::string* pStr) {
-
- // skip empty case
- if (pStr->empty())
- return;
-
- // trim right
- std::string::size_type pos = pStr->find_last_not_of(kWhitespaceChars);
- if (pos != std::string::npos)
- pStr->erase(pos + 1);
-
- // trim left
- pos = pStr->find_first_not_of(kWhitespaceChars);
- pStr->erase(0, pos);
- }
-
- // Strip balanced quotes from around a string (assumes already trimmed)
- void stripQuotes(std::string* pStr) {
- if (pStr->length() < 2)
- return;
- char quote = *(pStr->begin());
- if ( (quote == '\'' || quote == '\"') && (*(pStr->rbegin()) == quote) )
- *pStr = pStr->substr(1, pStr->length()-2);
- }
-
- // is the passed string quoted?
- bool isQuoted(const std::string& str) {
- if (str.length() < 2)
- return false;
- char quote = *(str.begin());
- return (quote == '\'' || quote == '\"') && (*(str.rbegin()) == quote);
- }
-
- // show a warning message
- void showWarning(const std::string& msg) {
- Rcpp::Function warning = Rcpp::Environment::base_env()["warning"];
- warning(msg, Rcpp::Named("call.") = false);
- }
-
-} // namespace attributes
-} // namespace Rcpp
-
-
-using namespace Rcpp::attributes;
-
-// Implementation helpers for sourceCppContext
-namespace {
-
- // Class that manages generation of source code for the sourceCpp dynlib
- class SourceCppDynlib {
- public:
- SourceCppDynlib() {}
-
- SourceCppDynlib(const std::string& cppSourcePath, Rcpp::List platform)
- : cppSourcePath_(cppSourcePath)
-
- {
- // get cpp source file info
- FileInfo cppSourceFilenameInfo(cppSourcePath_);
- if (!cppSourceFilenameInfo.exists())
- throw Rcpp::file_not_found(cppSourcePath_);
-
- // record the base name of the source file
- Rcpp::Function basename = Rcpp::Environment::base_env()["basename"];
- cppSourceFilename_ = Rcpp::as<std::string>(basename(cppSourcePath_));
-
- // get platform info
- fileSep_ = Rcpp::as<std::string>(platform["file.sep"]);
- dynlibExt_ = Rcpp::as<std::string>(platform["dynlib.ext"]);
-
- // generate temp directory
- Rcpp::Function tempfile = Rcpp::Environment::base_env()["tempfile"];
- buildDirectory_ = Rcpp::as<std::string>(tempfile("sourcecpp_"));
- std::replace(buildDirectory_.begin(), buildDirectory_.end(), '\\', '/');
- Rcpp::Function dircreate = Rcpp::Environment::base_env()["dir.create"];
- dircreate(buildDirectory_);
-
- // generate a random context id
- Rcpp::Function sample = Rcpp::Environment::base_env()["sample"];
- std::ostringstream ostr;
- ostr << "sourceCpp_" << Rcpp::as<int>(sample(100000, 1));
- contextId_ = ostr.str();
-
- // regenerate the source code
- regenerateSource();
- }
-
- bool isEmpty() const { return cppSourcePath_.empty(); }
-
- bool isBuilt() const { return FileInfo(dynlibPath()).exists(); };
-
- bool isSourceDirty() const {
- // source file out of date means we're dirty
- if (FileInfo(cppSourcePath_).lastModified() >
- FileInfo(generatedCppSourcePath()).lastModified())
- return true;
-
- // no dynlib means we're dirty
- if (!FileInfo(dynlibPath()).exists())
- return true;
-
- // not dirty
- return false;
- }
-
- void regenerateSource() {
-
- // copy the source file to the build dir
- Rcpp::Function filecopy = Rcpp::Environment::base_env()["file.copy"];
- filecopy(cppSourcePath_, generatedCppSourcePath(), true);
-
- // parse attributes
- SourceFileAttributesParser sourceAttributes(cppSourcePath_);
-
- // generate cpp for attributes and append them
- std::ostringstream ostr;
- generateCpp(ostr, sourceAttributes, false, contextId_);
- generatedCpp_ = ostr.str();
- std::ofstream cppOfs(generatedCppSourcePath().c_str(),
- std::ofstream::out | std::ofstream::app);
- if (cppOfs.fail())
- throw Rcpp::file_io_error(generatedCppSourcePath());
- cppOfs << generatedCpp_;
- cppOfs.close();
-
- // generate R for attributes and write it into the build directory
- std::ofstream rOfs(generatedRSourcePath().c_str(),
- std::ofstream::out | std::ofstream::trunc);
- if (rOfs.fail())
- throw Rcpp::file_io_error(generatedRSourcePath());
-
- // DLLInfo - hide using . and ensure uniqueness using contextId
- std::string dllInfo = "`." + contextId_ + "_DLLInfo`";
- rOfs << dllInfo << " <- dyn.load('" << dynlibPath() << "')"
- << std::endl << std::endl;
-
- // Generate R functions
- generateR(rOfs, sourceAttributes, dllInfo);
-
- // remove the DLLInfo
- rOfs << std::endl << "rm(" << dllInfo << ")"
- << std::endl;
-
- rOfs.close();
-
- // discover exported functions, and dependencies
- exportedFunctions_.clear();
- depends_.clear();
- for (SourceFileAttributesParser::const_iterator
- it = sourceAttributes.begin(); it != sourceAttributes.end(); ++it) {
- if (it->name() == kExportAttribute && !it->function().empty())
- exportedFunctions_.push_back(it->exportedName());
-
- else if (it->name() == kDependsAttribute) {
- for (size_t i = 0; i<it->params().size(); ++i)
- depends_.push_back(it->params()[i].name());
- }
- }
-
- // capture embededded R
- embeddedR_ = sourceAttributes.embeddedR();
- }
-
- const std::string& contextId() const {
- return contextId_;
- }
-
- const std::string& cppSourcePath() const {
- return cppSourcePath_;
- }
-
- std::string buildDirectory() const {
- return buildDirectory_;
- }
-
- std::string generatedCpp() const {
- return generatedCpp_;
- }
-
- std::string cppSourceFilename() const {
- return cppSourceFilename_;
- }
-
- std::string rSourceFilename() const {
- return cppSourceFilename() + ".R";
- }
-
- std::string dynlibFilename() const {
- return contextId() + dynlibExt_;
- }
-
- std::string dynlibPath() const {
- return buildDirectory_ + fileSep_ + dynlibFilename();
- }
-
- const std::vector<std::string>& exportedFunctions() const {
- return exportedFunctions_;
- }
-
- const std::vector<std::string>& depends() const { return depends_; };
-
- const std::vector<std::string>& embeddedR() const { return embeddedR_; }
-
- private:
-
- std::string generatedCppSourcePath() const {
- return buildDirectory_ + fileSep_ + cppSourceFilename();
- }
-
- std::string generatedRSourcePath() const {
- return buildDirectory_ + fileSep_ + rSourceFilename();
- }
-
- void generateR(std::ostream& ostr,
- const SourceFileAttributes& attributes,
- const std::string& dllInfo) const
- {
- // process each attribute
- for(std::vector<Attribute>::const_iterator
- it = attributes.begin(); it != attributes.end(); ++it) {
-
- // alias the attribute and function (bail if not export)
- const Attribute& attribute = *it;
- if (!attribute.isExportedFunction())
- continue;
- const Function& function = attribute.function();
-
- // export the function
- ostr << attribute.exportedName()
- << " <- Rcpp:::sourceCppFunction("
- << "function(" << generateRArgList(function) << ") {}, "
- << dllInfo << ", "
- << "'" << contextId_ + "_" + function.name()
- << "')" << std::endl;
- }
-
- }
-
- private:
- std::string cppSourcePath_;
- std::string generatedCpp_;
- std::string cppSourceFilename_;
- std::string contextId_;
- std::string buildDirectory_;
- std::string fileSep_;
- std::string dynlibExt_;
- std::vector<std::string> exportedFunctions_;
- std::vector<std::string> depends_;
- std::vector<std::string> embeddedR_;
- };
-
- // Dynlib cache that allows lookup by either file path or code contents
- class SourceCppDynlibCache {
-
- public:
- SourceCppDynlibCache() {}
-
- private:
- // prohibit copying
- SourceCppDynlibCache(const SourceCppDynlibCache&);
- SourceCppDynlibCache& operator=(const SourceCppDynlibCache&);
-
- public:
- // Insert into cache by file name
- SourceCppDynlib* insertFile(const std::string& file,
- const SourceCppDynlib& dynlib) {
- Entry entry;
- entry.file = file;
- entry.dynlib = dynlib;
- entries_.push_back(entry);
- return &(entries_.rbegin()->dynlib);
- }
-
- // Insert into cache by code
- SourceCppDynlib* insertCode(const std::string& code,
- const SourceCppDynlib& dynlib) {
- Entry entry;
- entry.code = code;
- entry.dynlib = dynlib;
- entries_.push_back(entry);
- return &(entries_.rbegin()->dynlib);
- }
-
- // Lookup by file
- SourceCppDynlib* lookupByFile(const std::string& file) {
- for (std::size_t i = 0; i < entries_.size(); i++) {
- if (entries_[i].file == file)
- return &(entries_[i].dynlib);
- }
-
- return NULL;
- }
-
- // Lookup by code
- SourceCppDynlib* lookupByCode(const std::string& code) {
- for (std::size_t i = 0; i < entries_.size(); i++) {
- if (entries_[i].code == code)
- return &(entries_[i].dynlib);
- }
-
- return NULL;
- }
-
- private:
- struct Entry {
- std::string file;
- std::string code;
- SourceCppDynlib dynlib;
- };
- std::vector<Entry> entries_;
- };
-
-} // anonymous namespace
-
-// Create temporary build directory, generate code as necessary, and return
-// the context required for the sourceCpp function to complete it's work
-RcppExport SEXP sourceCppContext(SEXP sFile, SEXP sCode, SEXP sPlatform) {
-BEGIN_RCPP
- // parameters
- std::string file = Rcpp::as<std::string>(sFile);
- std::string code = sCode != R_NilValue ? Rcpp::as<std::string>(sCode) : "";
- Rcpp::List platform = Rcpp::as<Rcpp::List>(sPlatform);
-
- // get dynlib (using cache if possible)
- static SourceCppDynlibCache s_dynlibCache;
- SourceCppDynlib* pDynlib = !code.empty() ? s_dynlibCache.lookupByCode(code)
- : s_dynlibCache.lookupByFile(file);
-
- // check dynlib build state
- bool buildRequired = false;
-
- // if there is no dynlib in the cache then create one
- if (pDynlib == NULL) {
- buildRequired = true;
- SourceCppDynlib newDynlib(file, platform);
- if (!code.empty())
- pDynlib = s_dynlibCache.insertCode(code, newDynlib);
- else
- pDynlib = s_dynlibCache.insertFile(file, newDynlib);
- }
-
- // if the cached dynlib is dirty then regenerate the source
- else if (pDynlib->isSourceDirty()) {
- buildRequired = true;
- pDynlib->regenerateSource();
- }
-
- // if the dynlib hasn't yet been built then note that
- else if (!pDynlib->isBuilt()) {
- buildRequired = true;
- }
-
- // return context as a list
- using namespace Rcpp;
- return List::create(
- _["contextId"] = pDynlib->contextId(),
- _["cppSourcePath"] = pDynlib->cppSourcePath(),
- _["buildRequired"] = buildRequired,
- _["buildDirectory"] = pDynlib->buildDirectory(),
- _["generatedCpp"] = pDynlib->generatedCpp(),
- _["exportedFunctions"] = pDynlib->exportedFunctions(),
- _["cppSourceFilename"] = pDynlib->cppSourceFilename(),
- _["rSourceFilename"] = pDynlib->rSourceFilename(),
- _["dynlibFilename"] = pDynlib->dynlibFilename(),
- _["dynlibPath"] = pDynlib->dynlibPath(),
- _["depends"] = pDynlib->depends(),
- _["embeddedR"] = pDynlib->embeddedR());
-END_RCPP
-}
-
-// Compile the attributes within the specified package directory into
-// RcppExports.cpp and RcppExports.R
-RcppExport SEXP compileAttributes(SEXP sPackageDir,
- SEXP sPackageName,
- SEXP sCppFiles,
- SEXP sCppFileBasenames,
- SEXP sIncludes,
- SEXP sVerbose,
- SEXP sPlatform) {
-BEGIN_RCPP
- // arguments
- std::string packageDir = Rcpp::as<std::string>(sPackageDir);
- std::string packageName = Rcpp::as<std::string>(sPackageName);
- std::vector<std::string> cppFiles =
- Rcpp::as<std::vector<std::string> >(sCppFiles);
- std::vector<std::string> cppFileBasenames =
- Rcpp::as<std::vector<std::string> >(sCppFileBasenames);
- std::vector<std::string> includes =
- Rcpp::as<std::vector<std::string> >(sIncludes);
- bool verbose = Rcpp::as<bool>(sVerbose);
- Rcpp::List platform = Rcpp::as<Rcpp::List>(sPlatform);
- std::string fileSep = Rcpp::as<std::string>(platform["file.sep"]);
-
- // initialize generators
- ExportsGenerators generators;
- generators.add(new CppExportsGenerator(packageDir, packageName, fileSep));
- generators.add(new RExportsGenerator(packageDir, packageName, fileSep));
-
- // catch file exists exception if the include file already exists
- // and we are unable to overwrite it
- try {
- generators.add(new CppExportsIncludeGenerator(packageDir,
- packageName,
- fileSep));
- }
- catch(const Rcpp::file_exists& e) {
- std::string msg =
- "The header file '" + e.filePath() + "' already exists so "
- "cannot be overwritten by Rcpp::interfaces";
- throw Rcpp::exception(msg.c_str(), __FILE__, __LINE__);
- }
-
- // catch file exists exception for package include (because if it
- // already exists we simply leave it alone)
- try {
- generators.add(new CppPackageIncludeGenerator(packageDir,
- packageName,
- fileSep));
- }
- catch(const Rcpp::file_exists& e) {}
-
- // write begin
- generators.writeBegin();
-
- // Parse attributes from each file and generate code as required.
- bool haveAttributes = false;
- for (std::size_t i=0; i<cppFiles.size(); i++) {
-
- // parse attributes (continue if there are none)
- std::string cppFile = cppFiles[i];
- SourceFileAttributesParser attributes(cppFile);
- if (attributes.empty())
- continue;
-
- // confirm we have attributes
- haveAttributes = true;
-
- // write functions
- generators.writeFunctions(attributes, verbose);
- }
-
- // write end
- generators.writeEnd();
-
- // commit or remove
- std::vector<std::string> updated;
- if (haveAttributes)
- updated = generators.commit(includes);
- else
- updated = generators.remove();
-
- // verbose output
- if (verbose) {
- for (size_t i=0; i<updated.size(); i++)
- Rcpp::Rcout << updated[i] << " updated." << std::endl;
- }
-
- // return files updated
- return Rcpp::wrap<std::vector<std::string> >(updated);
-END_RCPP
-}
-
+// -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; indent-tabs-mode: nil; -*-
+//
+// Attributes.cpp: Rcpp R/C++ interface class library -- Rcpp attributes
+//
+// Copyright (C) 2012 JJ Allaire, Dirk Eddelbuettel and Romain Francois
+//
+// This file is part of Rcpp.
+//
+// Rcpp is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 2 of the License, or
+// (at your option) any later version.
+//
+// Rcpp is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Rcpp. If not, see <http://www.gnu.org/licenses/>.
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#include <fstream>
+#include <cstring>
+#include <map>
+#include <algorithm>
+
+#include <Rcpp.h>
+
+#include "AttributesGen.h"
+#include "AttributesParser.h"
+#include "AttributesUtil.h"
+
+// provide implementations for util
+namespace Rcpp {
+namespace attributes {
+
+ // Utility class for getting file existence and last modified time
+ FileInfo::FileInfo(const std::string& path)
+ : path_(path), exists_(false), lastModified_(0)
+ {
+ #ifdef _WIN32
+ struct _stat buffer;
+ int result = _stat(path.c_str(), &buffer);
+ #else
+ struct stat buffer;
+ int result = stat(path.c_str(), &buffer);
+ #endif
+ if (result != 0) {
+ if (errno == ENOENT)
+ exists_ = false;
+ else
+ throw Rcpp::file_io_error(errno, path);
+ } else {
+ exists_ = true;
+ lastModified_ = buffer.st_mtime;
+ }
+ }
+
+ // Remove a file (call back into R for this)
+ bool removeFile(const std::string& path) {
+ if (FileInfo(path).exists()) {
+ Rcpp::Function rm = Rcpp::Environment::base_env()["file.remove"];
+ rm(path);
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+
+ // Recursively create a directory (call back into R for this)
+ void createDirectory(const std::string& path) {
+ if (!FileInfo(path).exists()) {
+ Rcpp::Function mkdir = Rcpp::Environment::base_env()["dir.create"];
+ mkdir(path, Rcpp::Named("recursive") = true);
+ }
+ }
+
+ // Known whitespace chars
+ const char * const kWhitespaceChars = " \f\n\r\t\v";
+
+ // Query whether a character is whitespace
+ bool isWhitespace(char ch) {
+ return std::strchr(kWhitespaceChars, ch) != NULL;
+ }
+
+ // Trim a string
+ void trimWhitespace(std::string* pStr) {
+
+ // skip empty case
+ if (pStr->empty())
+ return;
+
+ // trim right
+ std::string::size_type pos = pStr->find_last_not_of(kWhitespaceChars);
+ if (pos != std::string::npos)
+ pStr->erase(pos + 1);
+
+ // trim left
+ pos = pStr->find_first_not_of(kWhitespaceChars);
+ pStr->erase(0, pos);
+ }
+
+ // Strip balanced quotes from around a string (assumes already trimmed)
+ void stripQuotes(std::string* pStr) {
+ if (pStr->length() < 2)
+ return;
+ char quote = *(pStr->begin());
+ if ( (quote == '\'' || quote == '\"') && (*(pStr->rbegin()) == quote) )
+ *pStr = pStr->substr(1, pStr->length()-2);
+ }
+
+ // is the passed string quoted?
+ bool isQuoted(const std::string& str) {
+ if (str.length() < 2)
+ return false;
+ char quote = *(str.begin());
+ return (quote == '\'' || quote == '\"') && (*(str.rbegin()) == quote);
+ }
+
+ // show a warning message
+ void showWarning(const std::string& msg) {
+ Rcpp::Function warning = Rcpp::Environment::base_env()["warning"];
+ warning(msg, Rcpp::Named("call.") = false);
+ }
+
+} // namespace attributes
+} // namespace Rcpp
+
+
+using namespace Rcpp::attributes;
+
+// Implementation helpers for sourceCppContext
+namespace {
+
+ // Class that manages generation of source code for the sourceCpp dynlib
+ class SourceCppDynlib {
+ public:
+ SourceCppDynlib() {}
+
+ SourceCppDynlib(const std::string& cppSourcePath, Rcpp::List platform)
+ : cppSourcePath_(cppSourcePath)
+
+ {
+ // get cpp source file info
+ FileInfo cppSourceFilenameInfo(cppSourcePath_);
+ if (!cppSourceFilenameInfo.exists())
+ throw Rcpp::file_not_found(cppSourcePath_);
+
+ // record the base name of the source file
+ Rcpp::Function basename = Rcpp::Environment::base_env()["basename"];
+ cppSourceFilename_ = Rcpp::as<std::string>(basename(cppSourcePath_));
+
+ // get platform info
+ fileSep_ = Rcpp::as<std::string>(platform["file.sep"]);
+ dynlibExt_ = Rcpp::as<std::string>(platform["dynlib.ext"]);
+
+ // generate temp directory
+ Rcpp::Function tempfile = Rcpp::Environment::base_env()["tempfile"];
+ buildDirectory_ = Rcpp::as<std::string>(tempfile("sourcecpp_"));
+ std::replace(buildDirectory_.begin(), buildDirectory_.end(), '\\', '/');
+ Rcpp::Function dircreate = Rcpp::Environment::base_env()["dir.create"];
+ dircreate(buildDirectory_);
+
+ // generate a random context id
+ Rcpp::Function sample = Rcpp::Environment::base_env()["sample"];
+ std::ostringstream ostr;
+ ostr << "sourceCpp_" << Rcpp::as<int>(sample(100000, 1));
+ contextId_ = ostr.str();
+
+ // regenerate the source code
+ regenerateSource();
+ }
+
+ bool isEmpty() const { return cppSourcePath_.empty(); }
+
+ bool isBuilt() const { return FileInfo(dynlibPath()).exists(); };
+
+ bool isSourceDirty() const {
+ // source file out of date means we're dirty
+ if (FileInfo(cppSourcePath_).lastModified() >
+ FileInfo(generatedCppSourcePath()).lastModified())
+ return true;
+
+ // no dynlib means we're dirty
+ if (!FileInfo(dynlibPath()).exists())
+ return true;
+
+ // not dirty
+ return false;
+ }
+
+ void regenerateSource() {
+
+ // copy the source file to the build dir
+ Rcpp::Function filecopy = Rcpp::Environment::base_env()["file.copy"];
+ filecopy(cppSourcePath_, generatedCppSourcePath(), true);
+
+ // parse attributes
+ SourceFileAttributesParser sourceAttributes(cppSourcePath_);
+
+ // generate cpp for attributes and append them
+ std::ostringstream ostr;
+ // always include Rcpp.h in case the user didn't
+ ostr << std::endl << std::endl;
+ ostr << "#include <Rcpp.h>" << std::endl;
+ generateCpp(ostr, sourceAttributes, false, contextId_);
+ generatedCpp_ = ostr.str();
+ std::ofstream cppOfs(generatedCppSourcePath().c_str(),
+ std::ofstream::out | std::ofstream::app);
+ if (cppOfs.fail())
+ throw Rcpp::file_io_error(generatedCppSourcePath());
+ cppOfs << generatedCpp_;
+ cppOfs.close();
+
+ // generate R for attributes and write it into the build directory
+ std::ofstream rOfs(generatedRSourcePath().c_str(),
+ std::ofstream::out | std::ofstream::trunc);
+ if (rOfs.fail())
+ throw Rcpp::file_io_error(generatedRSourcePath());
+
+ // DLLInfo - hide using . and ensure uniqueness using contextId
+ std::string dllInfo = "`." + contextId_ + "_DLLInfo`";
+ rOfs << dllInfo << " <- dyn.load('" << dynlibPath() << "')"
+ << std::endl << std::endl;
+
+ // Generate R functions
+ generateR(rOfs, sourceAttributes, dllInfo);
+
+ // remove the DLLInfo
+ rOfs << std::endl << "rm(" << dllInfo << ")"
+ << std::endl;
+
+ rOfs.close();
+
+ // discover exported functions, and dependencies
+ exportedFunctions_.clear();
+ depends_.clear();
+ for (SourceFileAttributesParser::const_iterator
+ it = sourceAttributes.begin(); it != sourceAttributes.end(); ++it) {
+ if (it->name() == kExportAttribute && !it->function().empty())
+ exportedFunctions_.push_back(it->exportedName());
+
+ else if (it->name() == kDependsAttribute) {
+ for (size_t i = 0; i<it->params().size(); ++i)
+ depends_.push_back(it->params()[i].name());
+ }
+ }
+
+ // capture embededded R
+ embeddedR_ = sourceAttributes.embeddedR();
+ }
+
+ const std::string& contextId() const {
+ return contextId_;
+ }
+
+ const std::string& cppSourcePath() const {
+ return cppSourcePath_;
+ }
+
+ std::string buildDirectory() const {
+ return buildDirectory_;
+ }
+
+ std::string generatedCpp() const {
+ return generatedCpp_;
+ }
+
+ std::string cppSourceFilename() const {
+ return cppSourceFilename_;
+ }
+
+ std::string rSourceFilename() const {
+ return cppSourceFilename() + ".R";
+ }
+
+ std::string dynlibFilename() const {
+ return contextId() + dynlibExt_;
+ }
+
+ std::string dynlibPath() const {
+ return buildDirectory_ + fileSep_ + dynlibFilename();
+ }
+
+ const std::vector<std::string>& exportedFunctions() const {
+ return exportedFunctions_;
+ }
+
+ const std::vector<std::string>& depends() const { return depends_; };
+
+ const std::vector<std::string>& embeddedR() const { return embeddedR_; }
+
+ private:
+
+ std::string generatedCppSourcePath() const {
+ return buildDirectory_ + fileSep_ + cppSourceFilename();
+ }
+
+ std::string generatedRSourcePath() const {
+ return buildDirectory_ + fileSep_ + rSourceFilename();
+ }
+
+ void generateR(std::ostream& ostr,
+ const SourceFileAttributes& attributes,
+ const std::string& dllInfo) const
+ {
+ // process each attribute
+ for(std::vector<Attribute>::const_iterator
+ it = attributes.begin(); it != attributes.end(); ++it) {
+
+ // alias the attribute and function (bail if not export)
+ const Attribute& attribute = *it;
+ if (!attribute.isExportedFunction())
+ continue;
+ const Function& function = attribute.function();
+
+ // export the function
+ ostr << attribute.exportedName()
+ << " <- Rcpp:::sourceCppFunction("
+ << "function(" << generateRArgList(function) << ") {}, "
+ << dllInfo << ", "
+ << "'" << contextId_ + "_" + function.name()
+ << "')" << std::endl;
+ }
+
+ }
+
+ private:
+ std::string cppSourcePath_;
+ std::string generatedCpp_;
+ std::string cppSourceFilename_;
+ std::string contextId_;
+ std::string buildDirectory_;
+ std::string fileSep_;
+ std::string dynlibExt_;
+ std::vector<std::string> exportedFunctions_;
+ std::vector<std::string> depends_;
+ std::vector<std::string> embeddedR_;
+ };
+
+ // Dynlib cache that allows lookup by either file path or code contents
+ class SourceCppDynlibCache {
+
+ public:
+ SourceCppDynlibCache() {}
+
+ private:
+ // prohibit copying
+ SourceCppDynlibCache(const SourceCppDynlibCache&);
[TRUNCATED]
To get the complete diff run:
svnlook diff /svnroot/rcpp -r 4091
More information about the Rcpp-commits
mailing list