[Rcpp-commits] r3995 - in pkg/Rcpp: . inst man src

noreply at r-forge.r-project.org noreply at r-forge.r-project.org
Sun Nov 18 21:59:00 CET 2012


Author: jjallaire
Date: 2012-11-18 21:59:00 +0100 (Sun, 18 Nov 2012)
New Revision: 3995

Modified:
   pkg/Rcpp/ChangeLog
   pkg/Rcpp/TODO
   pkg/Rcpp/inst/NEWS.Rd
   pkg/Rcpp/man/interfacesAttribute.Rd
   pkg/Rcpp/src/Attributes.cpp
Log:
new scheme for mixing user and generated C++ headers

Modified: pkg/Rcpp/ChangeLog
===================================================================
--- pkg/Rcpp/ChangeLog	2012-11-18 16:54:19 UTC (rev 3994)
+++ pkg/Rcpp/ChangeLog	2012-11-18 20:59:00 UTC (rev 3995)
@@ -3,10 +3,12 @@
         * R/Attributes.R: sourceCpp embedded R code; print warning if 
         no export attributes are found in source file
         * src/AttributesParser.h: sourceCpp embedded R code
-        * src/AttributesParser.cpp: sourceCpp embedded R code
+        * src/AttributesParser.cpp: sourceCpp embedded R code; new scheme
+        for mixing user and generated C++ headers
         * src/Attributes.cpp: sourceCpp embedded R code; include <Rcpp.h>
         above generated modules
         * man/sourceCpp.Rd: documentation updates
+        * man/interfacesAttribute.Rd: documentation updates
 
 2012-11-18  Romain Francois <romain at r-enthusiasts.com>
 

Modified: pkg/Rcpp/TODO
===================================================================
--- pkg/Rcpp/TODO	2012-11-18 16:54:19 UTC (rev 3994)
+++ pkg/Rcpp/TODO	2012-11-18 20:59:00 UTC (rev 3995)
@@ -130,9 +130,6 @@
         Rcpp::depends attribute and do the right thing (use inline plugins
         to get the right Makevars, etc.)
     
-    o   Mechanism for users to include additional types and classes
-        in header generated by Rcpp::interfaces
-
     o   Add unit tests 
 
     o   Mechanism for specifying default values for exported R functions

Modified: pkg/Rcpp/inst/NEWS.Rd
===================================================================
--- pkg/Rcpp/inst/NEWS.Rd	2012-11-18 16:54:19 UTC (rev 3994)
+++ pkg/Rcpp/inst/NEWS.Rd	2012-11-18 20:59:00 UTC (rev 3995)
@@ -21,7 +21,9 @@
         \item Changes in Rcpp attributes: 
         \itemize{
             \item Ability to embed R code chunks (via specially formatted
-            block comments) in C++ source files.
+            block comments) in C++ source files
+            \item New scheme for more flexible mixing of user and generated
+            C++ headers
             \item Print warning if no export attributes are found in source file
         }
         \item Changes in R code :

Modified: pkg/Rcpp/man/interfacesAttribute.Rd
===================================================================
--- pkg/Rcpp/man/interfacesAttribute.Rd	2012-11-18 16:54:19 UTC (rev 3994)
+++ pkg/Rcpp/man/interfacesAttribute.Rd	2012-11-18 20:59:00 UTC (rev 3995)
@@ -22,7 +22,10 @@
     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.h}
+    \item Bindings are generated into a header file located in the \code{inst/include} directory of the package using the naming convention \emph{PackageName_RcppExports.h}
+    \item If not already present, an additional header file named \emph{PackageName.h} is also generated which in turn includes the Rcpp exports header. 
+    
+    In the case that you already have a \emph{PackageName.h} header for your package then you can manually add an include of the Rcpp exports header to it to make the exported functions available to users of your package.
     \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.
 }
@@ -46,7 +49,7 @@
 
     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.
+    A static naming scheme for generated header files and namespaces 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.
 
     The \code{Rcpp::interfaces} attribute is specified using a syntax compatible with the new \href{http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2761.pdf}{generalized attributes} feature of the C++11 standard. Note however that since this feature is not yet broadly supported by compilers it needs to be specified within a comment (see examples below).
 }

Modified: pkg/Rcpp/src/Attributes.cpp
===================================================================
--- pkg/Rcpp/src/Attributes.cpp	2012-11-18 16:54:19 UTC (rev 3994)
+++ pkg/Rcpp/src/Attributes.cpp	2012-11-18 20:59:00 UTC (rev 3995)
@@ -431,22 +431,21 @@
         std::vector<std::string> prototypes_;
         std::vector<std::string> signatures_;
     };
-    
-    // Class which manages generating the header file for the package
-    const char * const kTypesSuffix = "_types.h";
-    class CppIncludeGenerator : public ExportsGenerator {
+       
+    // Class which manages generating PackageName_RcppExports.h header file
+    const char * const kRcppExportsSuffix = "_RcppExports.h";
+    class CppExportsIncludeGenerator : public ExportsGenerator {
     public:
-        explicit CppIncludeGenerator(const std::string& packageDir, 
-                                     const std::string& package,
-                                     const std::string& fileSep)
+        CppExportsIncludeGenerator(const std::string& packageDir, 
+                                   const std::string& package,
+                                   const std::string& fileSep)
             : ExportsGenerator( 
                 packageDir +  fileSep + "inst" +  fileSep + "include" +
-                fileSep + package + ".h", 
+                fileSep + package + kRcppExportsSuffix, 
                 package,
                 "//")
         {
             includeDir_ = packageDir +  fileSep + "inst" +  fileSep + "include";
-            includeTypes_ = includeDir_ + fileSep + package + kTypesSuffix;
             hasCppInterface_ = false; 
         }
         
@@ -562,12 +561,6 @@
                     ostr << std::endl;
                 }
                 
-                // if there is a types header then include it as well
-                if (FileInfo(includeTypes_).exists()) {
-                    ostr << "#include <" << package() << kTypesSuffix << ">"
-                         << std::endl << std::endl;
-                }
-                
                 // commit with preamble
                 return ExportsGenerator::commit(ostr.str());
             }
@@ -593,10 +586,77 @@
         
     private:
         std::string includeDir_;
-        std::string includeTypes_;
         bool hasCppInterface_;
     };
     
+     // Class which manages generating PackageName_RcppExports.h header file
+    class CppPackageIncludeGenerator : public ExportsGenerator {
+    public:
+        CppPackageIncludeGenerator(const std::string& packageDir, 
+                                   const std::string& package,
+                                   const std::string& fileSep)
+            : ExportsGenerator( 
+                packageDir +  fileSep + "inst" +  fileSep + "include" +
+                fileSep + package + ".h", 
+                package,
+                "//")
+        {
+            includeDir_ = packageDir +  fileSep + "inst" +  fileSep + "include";
+            hasCppInterface_ = false; 
+        }
+        
+        virtual void writeBegin() {
+        }
+        
+        virtual void writeFunctions(const SourceFileAttributes &attributes,
+                                    bool verbose) {     
+            // See if there is a C++ interface exported by any attributes
+            if (attributes.hasInterface(kInterfaceCpp)) 
+                hasCppInterface_ = true;  
+        }
+        
+        virtual void writeEnd() {
+            if (hasCppInterface_) {
+                // header guard
+                std::string guard = getHeaderGuard();
+                ostr() << "#ifndef " << guard << std::endl;
+                ostr() << "#define " << guard << std::endl << std::endl; 
+                
+                ostr() << "#include \"" << package() << kRcppExportsSuffix 
+                       << "\"" << std::endl;
+                
+                ostr() << std::endl;
+                ostr() << "#endif // " << getHeaderGuard() << std::endl;
+            }
+        }
+        
+        virtual bool commit(const std::vector<std::string>& includes) {
+            
+            if (hasCppInterface_) {
+                
+                // create the include dir if necessary
+                createDirectory(includeDir_);
+                
+                // commit 
+                return ExportsGenerator::commit();
+            }
+            else {
+                return ExportsGenerator::remove();
+            }
+        }
+        
+    private:
+    
+        std::string getHeaderGuard() const {
+            return package() + "_h";
+        }
+        
+    private:
+        std::string includeDir_;
+        bool hasCppInterface_;
+    };
+    
+    
     // Class which manages generator RcppExports.R
     class RExportsGenerator : public ExportsGenerator {
     public:
@@ -763,9 +823,9 @@
     // catch file exists exception if the include file already exists
     // and we are unable to overwrite it
     try {
-        generators.add(new CppIncludeGenerator(packageDir, 
-                                               packageName, 
-                                               fileSep));
+        generators.add(new CppExportsIncludeGenerator(packageDir, 
+                                                      packageName, 
+                                                      fileSep));
     }
     catch(const Rcpp::file_exists& e) {
         std::string msg = 
@@ -774,6 +834,15 @@
         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();
      



More information about the Rcpp-commits mailing list