[thrift] Output dir selection + updated TSCons

Summary: Allows setting the output directory via the new '-o dir' cmdline option.

  TSCons is updated to use this to put the output in the right place no matter
  the cwd, so doing dependent builds from different directories won't break.

Reviewed By: martin
Test Plan: mkdir /tmp/honk; thrift -cpp -java -javabean -php -phpi -py -rb -xsd -perl -erl -ocaml -hs -cocoa -o /tmp/honk Tablet.thrift
Revert: svn


git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@665311 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/compiler/cpp/src/main.cc b/compiler/cpp/src/main.cc
index 0078055..468a7b0 100644
--- a/compiler/cpp/src/main.cc
+++ b/compiler/cpp/src/main.cc
@@ -21,6 +21,7 @@
 #include <string>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <errno.h>
 
 // Careful: must include globals first for extern definitions
 #include "globals.h"
@@ -566,6 +567,8 @@
   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");
@@ -770,6 +773,9 @@
   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]);
     }
   }
@@ -889,6 +895,7 @@
  */
 int main(int argc, char** argv) {
   int i;
+  std::string out_path;
 
   // Setup time string
   time_t now = time(NULL);
@@ -960,6 +967,22 @@
           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();
@@ -985,6 +1008,9 @@
 
   // 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);