*/
void t_cocoa_generator::init_generator() {
// Make output directory
- mkdir(T_COCOA_DIR, S_IREAD | S_IWRITE | S_IEXEC);
+ mkdir(get_out_dir().c_str(), S_IREAD | S_IWRITE | S_IEXEC);
cocoa_prefix_ = program_->get_cocoa_prefix();
// we have a .h header file...
string f_header_name = program_name_+".h";
- string f_header_fullname = string(T_COCOA_DIR)+"/"+f_header_name;
+ string f_header_fullname = get_out_dir()+f_header_name;
f_header_.open(f_header_fullname.c_str());
f_header_ <<
cocoa_thrift_imports();
// ...and a .m implementation file
- string f_impl_name = string(T_COCOA_DIR)+"/"+program_name_+".m";
+ string f_impl_name = get_out_dir()+program_name_+".m";
f_impl_.open(f_impl_name.c_str());
f_impl_ <<
#include "t_oop_generator.h"
-// TODO(mcslee: Paramaterize the output dir
-#define T_COCOA_DIR "gen-cocoa"
-
/**
* Objective-C code generator.
*
class t_cocoa_generator : public t_oop_generator {
public:
t_cocoa_generator(t_program* program) :
- t_oop_generator(program) {}
+ t_oop_generator(program) {
+ out_dir_base_ = "gen-cocoa";
+ }
/**
* Init and close methods
*/
void t_cpp_generator::init_generator() {
// Make output directory
- mkdir(T_CPP_DIR, S_IREAD | S_IWRITE | S_IEXEC);
+ mkdir(get_out_dir().c_str(), S_IREAD | S_IWRITE | S_IEXEC);
// Make output file
- string f_types_name = string(T_CPP_DIR)+"/"+program_name_+"_types.h";
+ string f_types_name = get_out_dir()+program_name_+"_types.h";
f_types_.open(f_types_name.c_str());
- string f_types_impl_name = string(T_CPP_DIR)+"/"+program_name_+"_types.cpp";
+ string f_types_impl_name = get_out_dir()+program_name_+"_types.cpp";
f_types_impl_.open(f_types_impl_name.c_str());
// Print header
* Generates a class that holds all the constants.
*/
void t_cpp_generator::generate_consts(std::vector<t_const*> consts) {
- string f_consts_name = string(T_CPP_DIR)+"/"+program_name_+"_constants.h";
+ string f_consts_name = get_out_dir()+program_name_+"_constants.h";
ofstream f_consts;
f_consts.open(f_consts_name.c_str());
- string f_consts_impl_name = string(T_CPP_DIR)+"/"+program_name_+"_constants.cpp";
+ string f_consts_impl_name = get_out_dir()+program_name_+"_constants.cpp";
ofstream f_consts_impl;
f_consts_impl.open(f_consts_impl_name.c_str());
string svcname = tservice->get_name();
// Make output files
- string f_header_name = string(T_CPP_DIR)+"/"+svcname+".h";
+ string f_header_name = get_out_dir()+svcname+".h";
f_header_.open(f_header_name.c_str());
// Print header file includes
endl;
// Service implementation file includes
- string f_service_name = string(T_CPP_DIR)+"/"+svcname+".cpp";
+ string f_service_name = get_out_dir()+svcname+".cpp";
f_service_.open(f_service_name.c_str());
f_service_ <<
autogen_comment();
string svcname = tservice->get_name();
// Service implementation file includes
- string f_skeleton_name = string(T_CPP_DIR)+"/"+svcname+"_server.skeleton.cpp";
+ string f_skeleton_name = get_out_dir()+svcname+"_server.skeleton.cpp";
string ns = namespace_prefix(tservice->get_program()->get_cpp_namespace());
#include "t_oop_generator.h"
-// TODO(mcslee): Paramaterize the output dir
-#define T_CPP_DIR "gen-cpp"
-
/**
* C++ code generator. This is legitimacy incarnate.
*
public:
t_cpp_generator(t_program* program, bool gen_dense) :
t_oop_generator(program),
- gen_dense_(gen_dense) {}
+ gen_dense_(gen_dense) {
+
+ out_dir_base_ = "gen-cpp";
+ }
/**
* Init and close methods
*/
void t_erl_generator::init_generator() {
// Make output directory
- mkdir(T_ERL_DIR, S_IREAD | S_IWRITE | S_IEXEC);
+ mkdir(get_out_dir().c_str(), S_IREAD | S_IWRITE | S_IEXEC);
// setup export lines
export_lines_first_ = true;
export_types_lines_first_ = true;
// types files
- string f_types_name = string(T_ERL_DIR)+"/"+program_name_+"_types.erl";
- string f_types_hrl_name = string(T_ERL_DIR)+"/"+program_name_+"_types.hrl";
+ string f_types_name = get_out_dir()+program_name_+"_types.erl";
+ string f_types_hrl_name = get_out_dir()+program_name_+"_types.hrl";
f_types_file_.open(f_types_name.c_str());
f_types_hrl_file_.open(f_types_hrl_name.c_str());
f_types_hrl_file_ << render_includes() << endl;
// consts file
- string f_consts_name = string(T_ERL_DIR)+"/"+program_name_+"_constants.hrl";
+ string f_consts_name = get_out_dir()+program_name_+"_constants.hrl";
f_consts_.open(f_consts_name.c_str());
f_consts_ <<
// ...awesome
service_name_[0] = tolower(service_name_[0]);
- string f_service_hrl_name = string(T_ERL_DIR)+"/"+service_name_+"_thrift.hrl";
- string f_service_name = string(T_ERL_DIR)+"/"+service_name_+"_thrift.erl";
+ string f_service_hrl_name = get_out_dir()+service_name_+"_thrift.hrl";
+ string f_service_name = get_out_dir()+service_name_+"_thrift.erl";
f_service_file_.open(f_service_name.c_str());
f_service_hrl_.open(f_service_hrl_name.c_str());
#include "t_oop_generator.h"
-#define T_ERL_DIR "gen-erl"
-
/**
* Erlang code generator.
*
{
program_name_[0] = tolower(program_name_[0]);
service_name_[0] = tolower(service_name_[0]);
+ out_dir_base_ = "gen-erl";
}
/**
return tservice->get_name();
}
+ /**
+ * Get the current output directory
+ */
+ virtual std::string get_out_dir() const {
+ return program_->get_out_path() + out_dir_base_ + "/";
+ }
+
/**
* Creates a unique temporary variable name, which is just "name" with a
* number appended to it (i.e. name35)
*/
std::string service_name_;
+ /**
+ * Output type-specifc directory name ("gen-*")
+ */
+ std::string out_dir_base_;
+
private:
/**
* Current code indentation level
*/
void t_hs_generator::init_generator() {
// Make output directory
- mkdir(T_HS_DIR, S_IREAD | S_IWRITE | S_IEXEC);
+ mkdir(get_out_dir().c_str(), S_IREAD | S_IWRITE | S_IEXEC);
// Make output file
string pname = capitalize(program_name_);
- string f_types_name = string(T_HS_DIR)+"/"+pname+"_Types.hs";
+ string f_types_name = get_out_dir()+pname+"_Types.hs";
f_types_.open(f_types_name.c_str());
- string f_consts_name = string(T_HS_DIR)+"/"+pname+"_Consts.hs";
+ string f_consts_name = get_out_dir()+pname+"_Consts.hs";
f_consts_.open(f_consts_name.c_str());
// Print header
* @param tservice The service definition
*/
void t_hs_generator::generate_service(t_service* tservice) {
- string f_service_name = string(T_HS_DIR)+"/"+capitalize(service_name_)+".hs";
+ string f_service_name = get_out_dir()+capitalize(service_name_)+".hs";
f_service_.open(f_service_name.c_str());
f_service_ <<
* @param tservice The service to generate a header definition for
*/
void t_hs_generator::generate_service_interface(t_service* tservice) {
- string f_iface_name = string(T_HS_DIR)+"/"+capitalize(service_name_)+"_Iface.hs";
+ string f_iface_name = get_out_dir()+capitalize(service_name_)+"_Iface.hs";
f_iface_.open(f_iface_name.c_str());
indent(f_iface_) << "module " << capitalize(service_name_) << "_Iface where" << endl;
* @param tservice The service to generate a server for.
*/
void t_hs_generator::generate_service_client(t_service* tservice) {
- string f_client_name = string(T_HS_DIR)+"/"+capitalize(service_name_)+"_Client.hs";
+ string f_client_name = get_out_dir()+capitalize(service_name_)+"_Client.hs";
f_client_.open(f_client_name.c_str());
vector<t_function*> functions = tservice->get_functions();
#include "t_oop_generator.h"
-#define T_HS_DIR "gen-hs"
-
/**
* Haskell code generator.
*
class t_hs_generator : public t_oop_generator {
public:
t_hs_generator(t_program* program) :
- t_oop_generator(program) {}
+ t_oop_generator(program) {
+
+ out_dir_base_ = "gen-hs";
+ }
/**
* Init and close methods
*/
void t_java_generator::init_generator() {
// Make output directory
- const char* java_dir = bean_style_ ? T_JAVABEAN_DIR : T_JAVA_DIR;
- mkdir(java_dir, S_IREAD | S_IWRITE | S_IEXEC);
+ mkdir(get_out_dir().c_str(), S_IREAD | S_IWRITE | S_IEXEC);
package_name_ = program_->get_java_package();
string dir = package_name_;
- string subdir = java_dir;
+ string subdir = get_out_dir();
string::size_type loc;
while ((loc = dir.find(".")) != string::npos) {
subdir = subdir + "/" + dir.substr(0, loc);
#include "t_oop_generator.h"
-// TODO(mcslee: Paramaterize the output dir
-#define T_JAVA_DIR "gen-java"
-#define T_JAVABEAN_DIR "gen-javabean"
-
/**
* Java code generator.
*
public:
t_java_generator(t_program* program, bool bean_style=false) :
t_oop_generator(program),
- bean_style_(bean_style) {}
+ bean_style_(bean_style) {
+
+ out_dir_base_ = (bean_style_ ? "gen-javabean" : "gen-java");
+ }
+
/**
* Init and close methods
*/
void t_ocaml_generator::init_generator() {
// Make output directory
- mkdir(T_OCAML_DIR, S_IREAD | S_IWRITE | S_IEXEC);
+ mkdir(get_out_dir().c_str(), S_IREAD | S_IWRITE | S_IEXEC);
// Make output file
- string f_types_name = string(T_OCAML_DIR)+"/"+program_name_+"_types.ml";
+ string f_types_name = get_out_dir()+program_name_+"_types.ml";
f_types_.open(f_types_name.c_str());
- string f_types_i_name = string(T_OCAML_DIR)+"/"+program_name_+"_types.mli";
+ string f_types_i_name = get_out_dir()+program_name_+"_types.mli";
f_types_i_.open(f_types_i_name.c_str());
- string f_consts_name = string(T_OCAML_DIR)+"/"+program_name_+"_consts.ml";
+ string f_consts_name = get_out_dir()+program_name_+"_consts.ml";
f_consts_.open(f_consts_name.c_str());
// Print header
* @param tservice The service definition
*/
void t_ocaml_generator::generate_service(t_service* tservice) {
- string f_service_name = string(T_OCAML_DIR)+"/"+capitalize(service_name_)+".ml";
+ string f_service_name = get_out_dir()+capitalize(service_name_)+".ml";
f_service_.open(f_service_name.c_str());
- string f_service_i_name = string(T_OCAML_DIR)+"/"+capitalize(service_name_)+".mli";
+ string f_service_i_name = get_out_dir()+capitalize(service_name_)+".mli";
f_service_i_.open(f_service_i_name.c_str());
f_service_ <<
#include "t_oop_generator.h"
-#define T_OCAML_DIR "gen-ocaml"
-
/**
* OCaml code generator.
*
class t_ocaml_generator : public t_oop_generator {
public:
t_ocaml_generator(t_program* program) :
- t_oop_generator(program) {}
+ t_oop_generator(program) {
+ out_dir_base_ = "gen-ocaml";
+ }
/**
* Init and close methods
*/
void t_perl_generator::init_generator() {
// Make output directory
- mkdir(T_PERL_DIR, S_IREAD | S_IWRITE | S_IEXEC);
+ mkdir(get_out_dir().c_str(), S_IREAD | S_IWRITE | S_IEXEC);
- string outdir(T_PERL_DIR);
+ string outdir = get_out_dir();
std::string ns = program_->get_perl_package();
if (ns.length() > 0) {
- outdir += "/" + ns;
+ outdir += ns + "/";
mkdir(outdir.c_str(), S_IREAD | S_IWRITE | S_IEXEC);
}
// Make output file
- string f_types_name = outdir+"/Types.pm";
+ string f_types_name = outdir+"Types.pm";
f_types_.open(f_types_name.c_str());
- string f_consts_name = outdir+"/Constants.pm";
+ string f_consts_name = outdir+"Constants.pm";
f_consts_.open(f_consts_name.c_str());
// Print header
* @param tservice The service definition
*/
void t_perl_generator::generate_service(t_service* tservice) {
- string f_service_name = string(T_PERL_DIR)+"/"+service_name_+".pm";
+ string f_service_name = get_out_dir()+service_name_+".pm";
f_service_.open(f_service_name.c_str());
f_service_ <<
public:
t_perl_generator(t_program* program) :
t_oop_generator(program) {
- T_PERL_DIR = "gen-perl";
+
+ out_dir_base_ = "gen-perl";
}
/**
private:
- /**
- * Output directory
- */
- char* T_PERL_DIR;
-
/**
* File streams
*/
*/
void t_php_generator::init_generator() {
// Make output directory
- mkdir(T_PHP_DIR, S_IREAD | S_IWRITE | S_IEXEC);
+ mkdir(get_out_dir().c_str(), S_IREAD | S_IWRITE | S_IEXEC);
// Make output file
- string f_types_name = string(T_PHP_DIR)+"/"+program_name_+"_types.php";
+ string f_types_name = get_out_dir()+program_name_+"_types.php";
f_types_.open(f_types_name.c_str());
- string f_consts_name = string(T_PHP_DIR)+"/"+program_name_+"_constants.php";
+ string f_consts_name = get_out_dir()+program_name_+"_constants.php";
f_consts_.open(f_consts_name.c_str());
// Print header
* @param tservice The service definition
*/
void t_php_generator::generate_service(t_service* tservice) {
- string f_service_name = string(T_PHP_DIR)+"/"+service_name_+".php";
+ string f_service_name = get_out_dir()+service_name_+".php";
f_service_.open(f_service_name.c_str());
f_service_ <<
t_oop_generator(program),
binary_inline_(binary_inline),
rest_(rest) {
- if (binary_inline_) {
- T_PHP_DIR = "gen-phpi";
- } else {
- T_PHP_DIR = "gen-php";
- }
+ out_dir_base_ = (binary_inline_ ? "gen-phpi" : "gen-php");
}
/**
private:
- /**
- * Output directory
- */
- char* T_PHP_DIR;
-
/**
* File streams
*/
void t_py_generator::init_generator() {
// Make output directory
string module = get_real_py_module(program_);
- package_dir_ = T_PY_DIR;
+ package_dir_ = get_out_dir();
while (true) {
// TODO: Do better error checking here.
mkdir(package_dir_.c_str(), S_IREAD | S_IWRITE | S_IEXEC);
#include "t_generator.h"
-#define T_PY_DIR "gen-py"
-
/**
* Python code generator.
*
class t_py_generator : public t_generator {
public:
t_py_generator(t_program* program) :
- t_generator(program) {}
+ t_generator(program) {
+ out_dir_base_ = "gen-py";
+ }
/**
* Init and close methods
*/
void t_rb_generator::init_generator() {
// Make output directory
- mkdir(T_RB_DIR, S_IREAD | S_IWRITE | S_IEXEC);
+ mkdir(get_out_dir().c_str(), S_IREAD | S_IWRITE | S_IEXEC);
// Make output file
- string f_types_name = string(T_RB_DIR)+"/"+program_name_+"_types.rb";
+ string f_types_name = get_out_dir()+program_name_+"_types.rb";
f_types_.open(f_types_name.c_str());
- string f_consts_name = string(T_RB_DIR)+"/"+program_name_+"_constants.rb";
+ string f_consts_name = get_out_dir()+program_name_+"_constants.rb";
f_consts_.open(f_consts_name.c_str());
// Print header
* @param tservice The service definition
*/
void t_rb_generator::generate_service(t_service* tservice) {
- string f_service_name = string(T_RB_DIR)+"/"+service_name_+".rb";
+ string f_service_name = get_out_dir()+service_name_+".rb";
f_service_.open(f_service_name.c_str());
f_service_ <<
#include "t_oop_generator.h"
-#define T_RB_DIR "gen-rb"
-
/**
* Ruby code generator.
*
class t_rb_generator : public t_oop_generator {
public:
t_rb_generator(t_program* program) :
- t_oop_generator(program) {}
+ t_oop_generator(program) {
+
+ out_dir_base_ = "gen-rb";
+ }
/**
* Init and close methods
void t_xsd_generator::init_generator() {
// Make output directory
- mkdir(T_XSD_DIR, S_IREAD | S_IWRITE | S_IEXEC);
+ mkdir(get_out_dir().c_str(), S_IREAD | S_IWRITE | S_IEXEC);
// Make output file
- string f_php_name = string(T_XSD_DIR)+"/"+program_->get_name()+"_xsd.php";
+ string f_php_name = get_out_dir()+program_->get_name()+"_xsd.php";
f_php_.open(f_php_name.c_str());
f_php_ <<
void t_xsd_generator::generate_service(t_service* tservice) {
// Make output file
- string f_xsd_name = string(T_XSD_DIR)+"/"+tservice->get_name()+".xsd";
+ string f_xsd_name = get_out_dir()+tservice->get_name()+".xsd";
f_xsd_.open(f_xsd_name.c_str());
string ns = program_->get_xsd_namespace();
#include <sstream>
#include "t_generator.h"
-// TODO(mcslee): Paramaterize the output dir
-#define T_XSD_DIR "gen-xsd"
-
/**
* XSD generator, creates an XSD for the base types etc.
*
class t_xsd_generator : public t_generator {
public:
t_xsd_generator(t_program* program) :
- t_generator(program) {}
+ t_generator(program) {
+ out_dir_base_ = "gen-xsd";
+ }
virtual ~t_xsd_generator() {}
#include <string>
#include <sys/types.h>
#include <sys/stat.h>
+#include <errno.h>
// Careful: must include globals first for extern definitions
#include "globals.h"
fprintf(stderr, " -ocaml Generate OCaml output files\n");
fprintf(stderr, " -hs Generate Haskell output files\n");
fprintf(stderr, " -cocoa Generate Cocoa/Objective-C output files\n");
+ fprintf(stderr, " -o dir Set the output directory for gen-* packages\n");
+ 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, " -dense Generate metadata for TDenseProtocol (C++)\n");
if (gen_recurse) {
const vector<t_program*>& includes = program->get_includes();
for (size_t i = 0; i < includes.size(); ++i) {
+ // Propogate output path from parent to child programs
+ includes[i]->set_out_path(program->get_out_path());
+
generate(includes[i]);
}
}
*/
int main(int argc, char** argv) {
int i;
+ std::string out_path;
// Setup time string
time_t now = time(NULL);
usage();
}
g_incl_searchpath.push_back(arg);
+ } else if (strcmp(arg, "-o") == 0) {
+ arg = argv[++i];
+ if (arg == NULL) {
+ fprintf(stderr, "-o: missing output directory");
+ usage();
+ }
+ out_path = arg;
+ struct stat sb;
+ if (stat(out_path.c_str(), &sb) < 0) {
+ fprintf(stderr, "Output directory %s is unusable: %s\n", out_path.c_str(), strerror(errno));
+ return -1;
+ }
+ if (! S_ISDIR(sb.st_mode)) {
+ fprintf(stderr, "Output directory %s exists but is not a directory\n", out_path.c_str());
+ return -1;
+ }
} else {
fprintf(stderr, "!!! Unrecognized option: %s\n", arg);
usage();
// Instance of the global parse tree
t_program* program = new t_program(input_file);
+ if (out_path.size()) {
+ program->set_out_path(out_path);
+ }
// Initialize global types
g_type_void = new t_base_type("void", t_base_type::TYPE_VOID);
public:
t_program(std::string path, std::string name) :
path_(path),
- name_(name) {
+ name_(name),
+ out_path_("./") {
scope_ = new t_scope();
}
t_program(std::string path) :
- path_(path) {
+ path_(path),
+ out_path_("./") {
name_ = program_name(path);
scope_ = new t_scope();
}
// Path accessor
const std::string& get_path() const { return path_; }
+ // Output path accessor
+ const std::string& get_out_path() const { return out_path_; }
+
// Name accessor
const std::string& get_name() const { return name_; }
// Programs to include
const std::vector<t_program*>& get_includes() const { return includes_; }
+ void set_out_path(std::string out_path) {
+ out_path_ = out_path;
+ // Ensure that it ends with a trailing '/' (or '\' for windows machines)
+ char c = out_path_.at(out_path_.size() - 1);
+ if (!(c == '/' || c == '\\')) {
+ out_path_.push_back('/');
+ }
+ }
+
// Scoping and namespacing
void set_namespace(std::string name) {
namespace_ = name;
// Name
std::string name_;
+ // Output directory
+ std::string out_path_;
+
// Namespace
std::string namespace_;
# See accompanying file LICENSE or visit the Thrift site at:
# http://developers.facebook.com/thrift/
+from os import path
from SCons.Builder import Builder
def scons_env(env, add=''):
- lstr = 'thrift --cpp ' + add + ' $SOURCE'
+ opath = path.dirname(path.abspath('$TARGET'))
+ lstr = 'thrift --cpp -o ' + opath + ' ' + add + ' $SOURCE'
cppbuild = Builder(action = lstr)
env.Append(BUILDERS = {'ThriftCpp' : cppbuild})