@@ -54,6 +54,14 @@ namespace attributes {
5454 bool exists () const { return exists_; }
5555 time_t lastModified () const { return lastModified_; }
5656
57+ std::string extension () const {
58+ std::string::size_type pos = path_.find_last_of (' .' );
59+ if (pos != std::string::npos)
60+ return path_.substr (pos);
61+ else
62+ return " " ;
63+ }
64+
5765 bool operator <(const FileInfo& other) const {
5866 return path_ < other.path_ ;
5967 };
@@ -143,7 +151,17 @@ namespace attributes {
143151 {
144152 }
145153 bool empty () const { return name ().empty (); }
146-
154+
155+ bool operator ==(const Type& other) const {
156+ return name_ == other.name_ &&
157+ isConst_ == other.isConst_ &&
158+ isReference_ == other.isReference_ ;
159+ };
160+
161+ bool operator !=(const Type& other) const {
162+ return !(*this == other);
163+ };
164+
147165 const std::string& name () const { return name_; }
148166 std::string full_name () const {
149167 std::string res ;
@@ -175,6 +193,17 @@ namespace attributes {
175193 }
176194
177195 bool empty () const { return type ().empty (); }
196+
197+ bool operator ==(const Argument& other) const {
198+ return name_ == other.name_ &&
199+ type_ == other.type_ &&
200+ defaultValue_ == other.defaultValue_ ;
201+ };
202+
203+ bool operator !=(const Argument& other) const {
204+ return !(*this == other);
205+ };
206+
178207
179208 const std::string& name () const { return name_; }
180209 const Type& type () const { return type_; }
@@ -192,14 +221,13 @@ namespace attributes {
192221 Function () {}
193222 Function (const Type& type,
194223 const std::string& name,
195- const std::vector<Argument>& arguments,
196- const std::string& source)
197- : type_(type), name_(name), arguments_(arguments), source_(source)
224+ const std::vector<Argument>& arguments)
225+ : type_(type), name_(name), arguments_(arguments)
198226 {
199227 }
200228
201229 Function renamedTo (const std::string& name) const {
202- return Function (type (), name, arguments (), source () );
230+ return Function (type (), name, arguments ());
203231 }
204232
205233 std::string signature () const { return signature (name ()); }
@@ -210,17 +238,25 @@ namespace attributes {
210238 }
211239
212240 bool empty () const { return name ().empty (); }
241+
242+ bool operator ==(const Function& other) const {
243+ return type_ == other.type_ &&
244+ name_ == other.name_ &&
245+ arguments_ == other.arguments_ ;
246+ };
247+
248+ bool operator !=(const Function& other) const {
249+ return !(*this == other);
250+ };
213251
214252 const Type& type () const { return type_; }
215253 const std::string& name () const { return name_; }
216254 const std::vector<Argument>& arguments () const { return arguments_; }
217- const std::string& source () const { return source_; }
218-
255+
219256 private:
220257 Type type_;
221258 std::string name_;
222259 std::vector<Argument> arguments_;
223- std::string source_;
224260 };
225261
226262 // Attribute parameter (with optional value)
@@ -229,6 +265,16 @@ namespace attributes {
229265 Param () {}
230266 explicit Param (const std::string& paramText);
231267 bool empty () const { return name ().empty (); }
268+
269+ bool operator ==(const Param& other) const {
270+ return name_ == other.name_ &&
271+ value_ == other.value_ ;
272+ };
273+
274+ bool operator !=(const Param& other) const {
275+ return !(*this == other);
276+ };
277+
232278
233279 const std::string& name () const { return name_; }
234280 const std::string& value () const { return value_; }
@@ -251,6 +297,18 @@ namespace attributes {
251297 }
252298
253299 bool empty () const { return name ().empty (); }
300+
301+ bool operator ==(const Attribute& other) const {
302+ return name_ == other.name_ &&
303+ params_ == other.params_ &&
304+ function_ == other.function_ &&
305+ roxygen_ == other.roxygen_ ;
306+ };
307+
308+ bool operator !=(const Attribute& other) const {
309+ return !(*this == other);
310+ };
311+
254312
255313 const std::string& name () const { return name_; }
256314
@@ -749,6 +807,9 @@ namespace attributes {
749807 Rcpp::Function filepath = baseEnv[" file.path" ];
750808 Rcpp::Function normalizePath = baseEnv[" normalizePath" ];
751809 Rcpp::Function fileExists = baseEnv[" file.exists" ];
810+ Rcpp::Environment toolsEnv = Rcpp::Environment::namespace_env (
811+ " tools" );
812+ Rcpp::Function filePathSansExt = toolsEnv[" file_path_sans_ext" ];
752813
753814 // get the path to the source file's directory
754815 Rcpp::CharacterVector sourceDir = dirname (sourceFile);
@@ -789,6 +850,25 @@ namespace attributes {
789850 newDependencies.push_back (
790851 FileInfo (Rcpp::as<std::string>(include)));
791852 }
853+
854+ std::vector<std::string> exts;
855+ exts.push_back (" .cc" );
856+ exts.push_back (" .cpp" );
857+ for (size_t i = 0 ; i<exts.size (); ++i) {
858+
859+ // look for corresponding cpp file and add it
860+ std::string file = Rcpp::as<std::string>(
861+ filePathSansExt (include)) + exts[i];
862+
863+ exists = fileExists (file);
864+ if (exists[0 ]) {
865+ if (addUniqueDependency (file,
866+ pDependencies)) {
867+ FileInfo fileInfo (file);
868+ newDependencies.push_back (fileInfo);
869+ }
870+ }
871+ }
792872 }
793873 }
794874 }
@@ -804,8 +884,17 @@ namespace attributes {
804884 // parse the source dependencies from the passed lines
805885 std::vector<FileInfo> parseSourceDependencies (
806886 const std::string& sourceFile) {
887+
888+ // parse dependencies
807889 std::vector<FileInfo> dependencies;
808890 parseSourceDependencies (sourceFile, &dependencies);
891+
892+ // remove main source file
893+ dependencies.erase (std::remove (dependencies.begin (),
894+ dependencies.end (),
895+ FileInfo (sourceFile)),
896+ dependencies.end ());
897+
809898 return dependencies;
810899 }
811900
@@ -912,22 +1001,32 @@ namespace attributes {
9121001 return os;
9131002 }
9141003
915- // Argument operator <<
916- std::ostream& operator <<(std::ostream& os, const Argument& argument) {
1004+ // Print argument
1005+ void printArgument (std::ostream& os,
1006+ const Argument& argument,
1007+ bool printDefault = true ) {
9171008 if (!argument.empty ()) {
9181009 os << argument.type ();
9191010 if (!argument.name ().empty ()) {
9201011 os << " " ;
9211012 os << argument.name ();
922- if (!argument.defaultValue ().empty ())
1013+ if (printDefault && !argument.defaultValue ().empty ())
9231014 os << " = " << argument.defaultValue ();
9241015 }
9251016 }
1017+ }
1018+
1019+ // Argument operator <<
1020+ std::ostream& operator <<(std::ostream& os, const Argument& argument) {
1021+ printArgument (os, argument);
9261022 return os;
9271023 }
9281024
929- // Function operator <<
930- std::ostream& operator <<(std::ostream& os, const Function& function) {
1025+ // Print function
1026+ void printFunction (std::ostream& os,
1027+ const Function& function,
1028+ bool printArgDefaults = true ) {
1029+
9311030 if (!function.empty ()) {
9321031 if (!function.type ().empty ()) {
9331032 os << function.type ();
@@ -937,12 +1036,17 @@ namespace attributes {
9371036 os << " (" ;
9381037 const std::vector<Argument>& arguments = function.arguments ();
9391038 for (std::size_t i = 0 ; i<arguments.size (); i++) {
940- os << arguments[i];
1039+ printArgument (os, arguments[i], printArgDefaults) ;
9411040 if (i != (arguments.size ()-1 ))
9421041 os << " , " ;
9431042 }
9441043 os << " )" ;
9451044 }
1045+ }
1046+
1047+ // Function operator <<
1048+ std::ostream& operator <<(std::ostream& os, const Function& function) {
1049+ printFunction (os, function);
9461050 return os;
9471051 }
9481052
@@ -1075,21 +1179,26 @@ namespace attributes {
10751179 // Recursively parse dependencies if requested
10761180 if (parseDependencies) {
10771181
1078- // get local includes
1182+ // get source dependencies
10791183 sourceDependencies_ = parseSourceDependencies (sourceFile);
10801184
1081- // parse attributes and modules from each local include
1185+ // parse attributes and modules from each dependent file
10821186 for (size_t i = 0 ; i<sourceDependencies_.size (); i++) {
10831187
10841188 // perform parse
10851189 std::string dependency = sourceDependencies_[i].path ();
10861190 SourceFileAttributesParser parser (dependency, false );
10871191
1088- // copy to base attributes
1089- std::copy (parser.begin (),
1090- parser.end (),
1091- std::back_inserter (attributes_));
1092-
1192+ // copy to base attributes (if it's a new attribute)
1193+ for (SourceFileAttributesParser::const_iterator
1194+ it = parser.begin (); it != parser.end (); ++it) {
1195+ if (std::find (attributes_.begin (),
1196+ attributes_.end (),
1197+ *it) == attributes_.end ()) {
1198+ attributes_.push_back (*it);
1199+ }
1200+ }
1201+
10931202 // copy to base modules
10941203 std::copy (parser.modules ().begin (),
10951204 parser.modules ().end (),
@@ -1339,7 +1448,7 @@ namespace attributes {
13391448 arguments.push_back (Argument (name, type, defaultValue));
13401449 }
13411450
1342- return Function (type, name, arguments, signature );
1451+ return Function (type, name, arguments);
13431452 }
13441453
13451454
@@ -2390,7 +2499,8 @@ namespace attributes {
23902499 // include prototype if requested
23912500 if (includePrototype) {
23922501 ostr << " // " << function.name () << std::endl;
2393- ostr << function << " ;" ;
2502+ printFunction (ostr, function, false );
2503+ ostr << " ;" ;
23942504 }
23952505
23962506 // write the C++ callable SEXP-based function (this version
@@ -2746,7 +2856,7 @@ namespace {
27462856 // always include Rcpp.h in case the user didn't
27472857 ostr << std::endl << std::endl;
27482858 ostr << " #include <Rcpp.h>" << std::endl;
2749- generateCpp (ostr, sourceAttributes, false , false , contextId_);
2859+ generateCpp (ostr, sourceAttributes, true , false , contextId_);
27502860 generatedCpp_ = ostr.str ();
27512861 std::ofstream cppOfs (generatedCppSourcePath ().c_str (),
27522862 std::ofstream::out | std::ofstream::app);
@@ -2813,6 +2923,17 @@ namespace {
28132923 const std::string& cppSourcePath () const {
28142924 return cppSourcePath_;
28152925 }
2926+
2927+ const std::vector<std::string> cppDependencySourcePaths () {
2928+ std::vector<std::string> dependencies;
2929+ for (size_t i = 0 ; i<sourceDependencies_.size (); ++i) {
2930+ FileInfo dep = sourceDependencies_[i];
2931+ if (dep.extension () == " .cc" || dep.extension () == " .cpp" ) {
2932+ dependencies.push_back (dep.path ());
2933+ }
2934+ }
2935+ return dependencies;
2936+ }
28162937
28172938 std::string buildDirectory () const {
28182939 return buildDirectory_;
@@ -3044,6 +3165,7 @@ BEGIN_RCPP
30443165 return List::create (
30453166 _[" contextId" ] = pDynlib->contextId (),
30463167 _[" cppSourcePath" ] = pDynlib->cppSourcePath (),
3168+ _[" cppDependencySourcePaths" ] = pDynlib->cppDependencySourcePaths (),
30473169 _[" buildRequired" ] = buildRequired,
30483170 _[" buildDirectory" ] = pDynlib->buildDirectory (),
30493171 _[" generatedCpp" ] = pDynlib->generatedCpp (),
0 commit comments