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;
// 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
"#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;
"#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_ <<
f_service_ <<
autogen_comment();
f_service_ <<
- "#include \"" << svcname << ".h\"" << endl <<
+ "#include \"" << get_include_prefix(*get_program()) << svcname << ".h\"" <<
+ endl <<
endl <<
ns_open_ << endl <<
endl;
"// 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 <<
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 "";
+}
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";
}
(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.
*/
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
*/
*/
void generate_program();
+ const t_program* get_program() const { return program_; }
+
protected:
/**
*/
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
*/
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");
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;
}
csharp->generate_program();
delete csharp;
}
-
+
if (dump_docs) {
dump_docstrings(program);
}
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];
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);
// 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_; }
// 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) {
// Included programs
std::vector<t_program*> includes_;
+ // Include prefix for this program, if any
+ std::string include_prefix_;
+
// Identifier lookup scope
t_scope* scope_;
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));
}
}
}