Skip to content

Commit 31be0ff

Browse files
committed
sourceCpp: automatically build implementation files (*.cc; *.cpp) corresponding to local header files if they exist
1 parent 2e17e39 commit 31be0ff

File tree

4 files changed

+131
-20
lines changed

4 files changed

+131
-20
lines changed

ChangeLog

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
* src/attributes.cpp: Guard against includes referencing themselves
44
(and thus creating an endless loop of include processing); Process
5-
attributes in included files.
5+
attributes in included files; Automatically build implementation files
6+
(*.cc; *.cpp) corresponding to local header files if they exist.
67

78
2015-02-20 Lionel Henry <[email protected]>
89

R/Attributes.R

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,10 @@ sourceCpp <- function(file = "",
114114
"-o ", shQuote(context$dynlibFilename), " ",
115115
ifelse(rebuild, "--preclean ", ""),
116116
ifelse(dryRun, "--dry-run ", ""),
117-
shQuote(context$cppSourceFilename), sep="")
117+
paste(shQuote(context$cppDependencySourcePaths),
118+
collapse = " "), " ",
119+
shQuote(context$cppSourceFilename), " ",
120+
sep="")
118121
if (showOutput)
119122
cat(cmd, "\n")
120123

inst/NEWS.Rd

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
\item The \code{pkg_types.h} file is now included in \code{RcppExports.cpp}
2121
if it is present in either the \code{inst/include} or \code{src}.
2222
\item \code{sourceCpp} was modified to allow includes of local files
23-
(e.g. #include "foo.hpp").
23+
(e.g. #include "foo.hpp"). Implementation files (*.cc; *.cpp) corresponding
24+
to local includes are also automatically built if they exist.
2425
\item The generated attributes code was simplified with respect to
2526
\code{RNGScope} and now uses \code{RObject} and its destructor rather than \code{SEXP}
2627
protect/unprotect.

src/attributes.cpp

Lines changed: 123 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -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

@@ -1075,21 +1164,26 @@ namespace attributes {
10751164
// Recursively parse dependencies if requested
10761165
if (parseDependencies) {
10771166

1078-
// get local includes
1167+
// get source dependencies
10791168
sourceDependencies_ = parseSourceDependencies(sourceFile);
10801169

1081-
// parse attributes and modules from each local include
1170+
// parse attributes and modules from each dependent file
10821171
for (size_t i = 0; i<sourceDependencies_.size(); i++) {
10831172

10841173
// perform parse
10851174
std::string dependency = sourceDependencies_[i].path();
10861175
SourceFileAttributesParser parser(dependency, false);
10871176

1088-
// copy to base attributes
1089-
std::copy(parser.begin(),
1090-
parser.end(),
1091-
std::back_inserter(attributes_));
1092-
1177+
// copy to base attributes (if it's a new attribute)
1178+
for (SourceFileAttributesParser::const_iterator
1179+
it = parser.begin(); it != parser.end(); ++it) {
1180+
if (std::find(attributes_.begin(),
1181+
attributes_.end(),
1182+
*it) == attributes_.end()) {
1183+
attributes_.push_back(*it);
1184+
}
1185+
}
1186+
10931187
// copy to base modules
10941188
std::copy(parser.modules().begin(),
10951189
parser.modules().end(),
@@ -1339,7 +1433,7 @@ namespace attributes {
13391433
arguments.push_back(Argument(name, type, defaultValue));
13401434
}
13411435

1342-
return Function(type, name, arguments, signature);
1436+
return Function(type, name, arguments);
13431437
}
13441438

13451439

@@ -2746,7 +2840,7 @@ namespace {
27462840
// always include Rcpp.h in case the user didn't
27472841
ostr << std::endl << std::endl;
27482842
ostr << "#include <Rcpp.h>" << std::endl;
2749-
generateCpp(ostr, sourceAttributes, false, false, contextId_);
2843+
generateCpp(ostr, sourceAttributes, true, false, contextId_);
27502844
generatedCpp_ = ostr.str();
27512845
std::ofstream cppOfs(generatedCppSourcePath().c_str(),
27522846
std::ofstream::out | std::ofstream::app);
@@ -2813,6 +2907,17 @@ namespace {
28132907
const std::string& cppSourcePath() const {
28142908
return cppSourcePath_;
28152909
}
2910+
2911+
const std::vector<std::string> cppDependencySourcePaths() {
2912+
std::vector<std::string> dependencies;
2913+
for (size_t i = 0; i<sourceDependencies_.size(); ++i) {
2914+
FileInfo dep = sourceDependencies_[i];
2915+
if (dep.extension() == ".cc" || dep.extension() == ".cpp") {
2916+
dependencies.push_back(dep.path());
2917+
}
2918+
}
2919+
return dependencies;
2920+
}
28162921

28172922
std::string buildDirectory() const {
28182923
return buildDirectory_;
@@ -3044,6 +3149,7 @@ BEGIN_RCPP
30443149
return List::create(
30453150
_["contextId"] = pDynlib->contextId(),
30463151
_["cppSourcePath"] = pDynlib->cppSourcePath(),
3152+
_["cppDependencySourcePaths"] = pDynlib->cppDependencySourcePaths(),
30473153
_["buildRequired"] = buildRequired,
30483154
_["buildDirectory"] = pDynlib->buildDirectory(),
30493155
_["generatedCpp"] = pDynlib->generatedCpp(),

0 commit comments

Comments
 (0)