thrift: Add -cpp_use_include_prefix flag to compiler
Summary: Adds a new flag to allow for a mode where #include statements in generated c++ will include path context information. For example, if my .thrift file includes "foo/bar/baz.thrift", the generated source files will contain #include statements like:
#include "foo/bar/gen-cpp/baz_types.h"
instead of just:
#include "baz_types.h"
-cpp_use_include_prefix is OFF by default.
Reviewed By: dreiss
Test Plan: Tested against multiple thrift input files both with and without the new flag.
Revert: OK
DiffCamp Revision: 5522
git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@665431 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/compiler/cpp/src/generate/t_cpp_generator.cc b/compiler/cpp/src/generate/t_cpp_generator.cc
index 620d09e..7200b55 100644
--- a/compiler/cpp/src/generate/t_cpp_generator.cc
+++ b/compiler/cpp/src/generate/t_cpp_generator.cc
@@ -54,7 +54,8 @@
const vector<t_program*>& includes = program_->get_includes();
for (size_t i = 0; i < includes.size(); ++i) {
f_types_ <<
- "#include \"" << includes[i]->get_name() << "_types.h\"" << endl;
+ "#include \"" << get_include_prefix(*(includes[i])) <<
+ includes[i]->get_name() << "_types.h\"" << endl;
}
f_types_ << endl;
@@ -69,7 +70,8 @@
// Include the types file
f_types_impl_ <<
- "#include \"" << program_name_ << "_types.h\"" << endl <<
+ "#include \"" << get_include_prefix(*get_program()) << program_name_ <<
+ "_types.h\"" << endl <<
endl;
// If we are generating local reflection metadata, we need to include
@@ -183,13 +185,15 @@
"#ifndef " << program_name_ << "_CONSTANTS_H" << endl <<
"#define " << program_name_ << "_CONSTANTS_H" << endl <<
endl <<
- "#include \"" << program_name_ << "_types.h\"" << endl <<
+ "#include \"" << get_include_prefix(*get_program()) << program_name_ <<
+ "_types.h\"" << endl <<
endl <<
ns_open_ << endl <<
endl;
f_consts_impl <<
- "#include \"" << program_name_ << "_constants.h\"" << endl <<
+ "#include \"" << get_include_prefix(*get_program()) << program_name_ <<
+ "_constants.h\"" << endl <<
endl <<
ns_open_ << endl <<
endl;
@@ -1014,11 +1018,14 @@
"#define " << svcname << "_H" << endl <<
endl <<
"#include <TProcessor.h>" << endl <<
- "#include \"" << program_name_ << "_types.h\"" << endl;
+ "#include \"" << get_include_prefix(*get_program()) << program_name_ <<
+ "_types.h\"" << endl;
- if (tservice->get_extends() != NULL) {
+ t_service* extends_service = tservice->get_extends();
+ if (extends_service != NULL) {
f_header_ <<
- "#include \"" << tservice->get_extends()->get_name() << ".h\"" << endl;
+ "#include \"" << get_include_prefix(*(extends_service->get_program())) <<
+ extends_service->get_name() << ".h\"" << endl;
}
f_header_ <<
@@ -1032,7 +1039,8 @@
f_service_ <<
autogen_comment();
f_service_ <<
- "#include \"" << svcname << ".h\"" << endl <<
+ "#include \"" << get_include_prefix(*get_program()) << svcname << ".h\"" <<
+ endl <<
endl <<
ns_open_ << endl <<
endl;
@@ -2076,7 +2084,7 @@
"// This autogenerated skeleton file illustrates how to build a server." << endl <<
"// You should copy it to another filename to avoid overwriting it." << endl <<
endl <<
- "#include \"" << svcname << ".h\"" << endl <<
+ "#include \"" << get_include_prefix(*get_program()) << svcname << ".h\"" << endl <<
"#include <protocol/TBinaryProtocol.h>" << endl <<
"#include <server/TSimpleServer.h>" << endl <<
"#include <transport/TServerSocket.h>" << endl <<
@@ -2867,3 +2875,19 @@
return string() + "trlo_" + prefix + "_" + prog + "_" + name;
}
+
+string t_cpp_generator::get_include_prefix(const t_program& program) const {
+ string include_prefix = program.get_include_prefix();
+ if (!use_include_prefix_ ||
+ (include_prefix.size() > 0 && include_prefix[0] == '/')) {
+ // if flag is turned off or this is absolute path, return empty prefix
+ return "";
+ }
+
+ string::size_type last_slash = string::npos;
+ if ((last_slash = include_prefix.rfind("/")) != string::npos) {
+ return include_prefix.substr(0, last_slash) + "/" + out_dir_base_ + "/";
+ }
+
+ return "";
+}
diff --git a/compiler/cpp/src/generate/t_cpp_generator.h b/compiler/cpp/src/generate/t_cpp_generator.h
index 574a7d2..4bc9783 100644
--- a/compiler/cpp/src/generate/t_cpp_generator.h
+++ b/compiler/cpp/src/generate/t_cpp_generator.h
@@ -23,7 +23,8 @@
public:
t_cpp_generator(t_program* program, bool gen_dense) :
t_oop_generator(program),
- gen_dense_(gen_dense) {
+ gen_dense_(gen_dense),
+ use_include_prefix_(false) {
out_dir_base_ = "gen-cpp";
}
@@ -163,7 +164,16 @@
(ttype->is_base_type() && (((t_base_type*)ttype)->get_base() == t_base_type::TYPE_STRING));
}
+ void set_use_include_prefix(bool use_include_prefix) {
+ use_include_prefix_ = use_include_prefix;
+ }
+
private:
+ /**
+ * Returns the include prefix to use for a file generated by program, or the
+ * empty string if no include prefix should be used.
+ */
+ std::string get_include_prefix(const t_program& program) const;
/**
* True iff we should generate local reflection metadata for TDenseProtocol.
@@ -171,6 +181,12 @@
bool gen_dense_;
/**
+ * True iff we should use a path prefix in our #include statements for other
+ * thrift-generated header files.
+ */
+ bool use_include_prefix_;
+
+ /**
* Strings for namespace, computed once up front then used directly
*/
diff --git a/compiler/cpp/src/generate/t_generator.h b/compiler/cpp/src/generate/t_generator.h
index 72ef144..734e033 100644
--- a/compiler/cpp/src/generate/t_generator.h
+++ b/compiler/cpp/src/generate/t_generator.h
@@ -38,6 +38,8 @@
*/
void generate_program();
+ const t_program* get_program() const { return program_; }
+
protected:
/**
diff --git a/compiler/cpp/src/main.cc b/compiler/cpp/src/main.cc
index 131820a..e0eb4b7 100644
--- a/compiler/cpp/src/main.cc
+++ b/compiler/cpp/src/main.cc
@@ -106,6 +106,12 @@
vector<string> g_incl_searchpath;
/**
+ * Should C++ include statements use path prefixes for other thrift-generated
+ * header files
+ */
+bool g_cpp_use_include_prefix = false;
+
+/**
* Global debug state
*/
int g_debug = 0;
@@ -613,6 +619,8 @@
fprintf(stderr, " (default: current directory)\n");
fprintf(stderr, " -I dir Add a directory to the list of directories\n");
fprintf(stderr, " searched for include directives\n");
+ fprintf(stderr, " -cpp_use_include_prefix\n");
+ fprintf(stderr, " Make C++ include statements use path prefixes\n");
fprintf(stderr, " -dense Generate metadata for TDenseProtocol (C++)\n");
fprintf(stderr, " -rest Generate PHP REST processors (with -php)\n");
fprintf(stderr, " -nowarn Suppress all compiler warnings (BAD!)\n");
@@ -832,6 +840,7 @@
if (gen_cpp) {
pverbose("Generating C++\n");
t_cpp_generator* cpp = new t_cpp_generator(program, gen_dense);
+ cpp->set_use_include_prefix(g_cpp_use_include_prefix);
cpp->generate_program();
delete cpp;
}
@@ -933,7 +942,7 @@
csharp->generate_program();
delete csharp;
}
-
+
if (dump_docs) {
dump_docstrings(program);
}
@@ -1034,6 +1043,8 @@
gen_st = true;
} else if (strcmp(arg, "-csharp") == 0) {
gen_csharp = true;
+ } else if (strcmp(arg, "-cpp_use_include_prefix") == 0) {
+ g_cpp_use_include_prefix = true;
} else if (strcmp(arg, "-I") == 0) {
// An argument of "-I\ asdf" is invalid and has unknown results
arg = argv[++i];
@@ -1097,6 +1108,18 @@
if (out_path.size()) {
program->set_out_path(out_path);
}
+ if (g_cpp_use_include_prefix) {
+ // infer this from the filename passed in
+ string input_filename = argv[i];
+ string include_prefix;
+
+ string::size_type last_slash = string::npos;
+ if ((last_slash = input_filename.rfind("/")) != string::npos) {
+ include_prefix = input_filename.substr(0, last_slash);
+ }
+
+ program->set_include_prefix(include_prefix);
+ }
// Initialize global types
g_type_void = new t_base_type("void", t_base_type::TYPE_VOID);
diff --git a/compiler/cpp/src/parse/t_program.h b/compiler/cpp/src/parse/t_program.h
index 62528e6..7b369d6 100644
--- a/compiler/cpp/src/parse/t_program.h
+++ b/compiler/cpp/src/parse/t_program.h
@@ -70,6 +70,9 @@
// Namespace
const std::string& get_namespace() const { return namespace_; }
+ // Include prefix accessor
+ const std::string& get_include_prefix() const { return include_prefix_; }
+
// Accessors for program elements
const std::vector<t_typedef*>& get_typedefs() const { return typedefs_; }
const std::vector<t_enum*>& get_enums() const { return enums_; }
@@ -113,14 +116,35 @@
// Includes
- void add_include(std::string path) {
- includes_.push_back(new t_program(path));
+ void add_include(std::string path, std::string include_site) {
+ t_program* program = new t_program(path);
+
+ // include prefix for this program is the site at which it was included
+ // (minus the filename)
+ std::string include_prefix;
+ std::string::size_type last_slash = std::string::npos;
+ if ((last_slash = include_site.rfind("/")) != std::string::npos) {
+ include_prefix = include_site.substr(0, last_slash);
+ }
+
+ program->set_include_prefix(include_prefix);
+ includes_.push_back(program);
}
std::vector<t_program*>& get_includes() {
return includes_;
}
+ void set_include_prefix(std::string include_prefix) {
+ include_prefix_ = include_prefix;
+
+ // this is intended to be a directory; add a trailing slash if necessary
+ int len = include_prefix_.size();
+ if (len > 0 && include_prefix_[len - 1] != '/') {
+ include_prefix_ += '/';
+ }
+ }
+
// Language specific namespace / packaging
void set_cpp_namespace(std::string cpp_namespace) {
@@ -236,6 +260,9 @@
// Included programs
std::vector<t_program*> includes_;
+ // Include prefix for this program, if any
+ std::string include_prefix_;
+
// Identifier lookup scope
t_scope* scope_;
diff --git a/compiler/cpp/src/thrifty.yy b/compiler/cpp/src/thrifty.yy
index 5be19b3..2b09972 100644
--- a/compiler/cpp/src/thrifty.yy
+++ b/compiler/cpp/src/thrifty.yy
@@ -347,7 +347,7 @@
if (g_parse_mode == INCLUDES) {
std::string path = include_file(std::string($2));
if (!path.empty()) {
- g_program->add_include(path);
+ g_program->add_include(path, std::string($2));
}
}
}