Thrift: MinGW port.
Summary:
Todd Berman from imeem has contributed a patch that allows
the Thrift compiler to be built with MinGW and run on Windows.
Reviewed By: mcslee
Test Plan:
Built the compiler from scratch on Linux.
If my changes messed up the MinGW build, I'm sure Todd will yell at me.
Revert Plan: ok
git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@665420 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/compiler/cpp/src/generate/t_cocoa_generator.cc b/compiler/cpp/src/generate/t_cocoa_generator.cc
index fc85365..1356c35 100644
--- a/compiler/cpp/src/generate/t_cocoa_generator.cc
+++ b/compiler/cpp/src/generate/t_cocoa_generator.cc
@@ -8,6 +8,7 @@
#include <sys/stat.h>
#include <sstream>
#include "t_cocoa_generator.h"
+#include "platform.h"
using namespace std;
/**
@@ -16,7 +17,7 @@
*/
void t_cocoa_generator::init_generator() {
// Make output directory
- mkdir(get_out_dir().c_str(), S_IRWXU | S_IRWXG | S_IRWXO);
+ MKDIR(get_out_dir().c_str());
cocoa_prefix_ = program_->get_cocoa_prefix();
// we have a .h header file...
diff --git a/compiler/cpp/src/generate/t_cpp_generator.cc b/compiler/cpp/src/generate/t_cpp_generator.cc
index c465426..620d09e 100644
--- a/compiler/cpp/src/generate/t_cpp_generator.cc
+++ b/compiler/cpp/src/generate/t_cpp_generator.cc
@@ -10,6 +10,7 @@
#include <sstream>
#include <boost/lexical_cast.hpp>
#include "t_cpp_generator.h"
+#include "platform.h"
using namespace std;
/**
@@ -20,7 +21,7 @@
*/
void t_cpp_generator::init_generator() {
// Make output directory
- mkdir(get_out_dir().c_str(), S_IRWXU | S_IRWXG | S_IRWXO);
+ MKDIR(get_out_dir().c_str());
// Make output file
string f_types_name = get_out_dir()+program_name_+"_types.h";
@@ -462,7 +463,7 @@
// Isset struct has boolean fields, but only for non-required fields.
bool has_nonrequired_fields = false;
for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
- if ((*m_iter)->get_req() != t_field::REQUIRED)
+ if ((*m_iter)->get_req() != t_field::T_REQUIRED)
has_nonrequired_fields = true;
}
@@ -476,7 +477,7 @@
"__isset() : ";
bool first = true;
for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
- if ((*m_iter)->get_req() == t_field::REQUIRED) {
+ if ((*m_iter)->get_req() == t_field::T_REQUIRED) {
continue;
}
if (first) {
@@ -491,7 +492,7 @@
out << " {}" << endl;
for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
- if ((*m_iter)->get_req() != t_field::REQUIRED) {
+ if ((*m_iter)->get_req() != t_field::T_REQUIRED) {
indent(out) <<
"bool " << (*m_iter)->get_name() << ";" << endl;
}
@@ -513,7 +514,7 @@
for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
// Most existing Thrift code does not use isset or optional/required,
// so we treat "default" fields as required.
- if ((*m_iter)->get_req() != t_field::OPTIONAL) {
+ if ((*m_iter)->get_req() != t_field::T_OPTIONAL) {
out <<
indent() << "if (!(" << (*m_iter)->get_name()
<< " == rhs." << (*m_iter)->get_name() << "))" << endl <<
@@ -638,7 +639,7 @@
indent_up();
for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
indent(out) << "{ " << (*m_iter)->get_key() << ", " <<
- (((*m_iter)->get_req() == t_field::OPTIONAL) ? "true" : "false") <<
+ (((*m_iter)->get_req() == t_field::T_OPTIONAL) ? "true" : "false") <<
" }," << endl;
}
// Zero for the T_STOP marker.
@@ -751,7 +752,7 @@
// Required variables aren't in __isset, so we need tmp vars to check them.
for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
- if ((*f_iter)->get_req() == t_field::REQUIRED)
+ if ((*f_iter)->get_req() == t_field::T_REQUIRED)
indent(out) << "bool isset_" << (*f_iter)->get_name() << " = false;" << endl;
}
out << endl;
@@ -788,7 +789,7 @@
indent_up();
const char *isset_prefix =
- ((*f_iter)->get_req() != t_field::REQUIRED) ? "this->__isset." : "isset_";
+ ((*f_iter)->get_req() != t_field::T_REQUIRED) ? "this->__isset." : "isset_";
#if 0
// This code throws an exception if the same field is encountered twice.
@@ -842,7 +843,7 @@
// there might possibly be a chance of continuing.
out << endl;
for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
- if ((*f_iter)->get_req() == t_field::REQUIRED)
+ if ((*f_iter)->get_req() == t_field::T_REQUIRED)
out <<
indent() << "if (!isset_" << (*f_iter)->get_name() << ')' << endl <<
indent() << " throw TProtocolException(TProtocolException::INVALID_DATA);" << endl;
@@ -878,7 +879,7 @@
indent(out) <<
"xfer += oprot->writeStructBegin(\"" << name << "\");" << endl;
for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
- if ((*f_iter)->get_req() == t_field::OPTIONAL) {
+ if ((*f_iter)->get_req() == t_field::T_OPTIONAL) {
indent(out) << "if (this->__isset." << (*f_iter)->get_name() << ") {" << endl;
indent_up();
}
@@ -897,7 +898,7 @@
// Write field closer
indent(out) <<
"xfer += oprot->writeFieldEnd();" << endl;
- if ((*f_iter)->get_req() == t_field::OPTIONAL) {
+ if ((*f_iter)->get_req() == t_field::T_OPTIONAL) {
indent_down();
indent(out) << '}' << endl;
}
diff --git a/compiler/cpp/src/generate/t_erl_generator.cc b/compiler/cpp/src/generate/t_erl_generator.cc
index 44683cd..02d7361 100644
--- a/compiler/cpp/src/generate/t_erl_generator.cc
+++ b/compiler/cpp/src/generate/t_erl_generator.cc
@@ -9,6 +9,7 @@
#include <sys/types.h>
#include <sstream>
#include "t_erl_generator.h"
+#include "platform.h"
using namespace std;
@@ -20,7 +21,7 @@
*/
void t_erl_generator::init_generator() {
// Make output directory
- mkdir(get_out_dir().c_str(), S_IRWXU | S_IRWXG | S_IRWXO);
+ MKDIR(get_out_dir().c_str());
// setup export lines
export_lines_first_ = true;
diff --git a/compiler/cpp/src/generate/t_hs_generator.cc b/compiler/cpp/src/generate/t_hs_generator.cc
index 8746ba4..6ef7a95 100644
--- a/compiler/cpp/src/generate/t_hs_generator.cc
+++ b/compiler/cpp/src/generate/t_hs_generator.cc
@@ -9,6 +9,7 @@
#include <sys/types.h>
#include <sstream>
#include "t_hs_generator.h"
+#include "platform.h"
using namespace std;
/*
@@ -72,7 +73,7 @@
*/
void t_hs_generator::init_generator() {
// Make output directory
- mkdir(get_out_dir().c_str(), S_IRWXU | S_IRWXG | S_IRWXO);
+ MKDIR(get_out_dir().c_str());
// Make output file
diff --git a/compiler/cpp/src/generate/t_java_generator.cc b/compiler/cpp/src/generate/t_java_generator.cc
index e0a1be2..cd4b873 100644
--- a/compiler/cpp/src/generate/t_java_generator.cc
+++ b/compiler/cpp/src/generate/t_java_generator.cc
@@ -8,6 +8,7 @@
#include <sys/stat.h>
#include <sstream>
#include "t_java_generator.h"
+#include "platform.h"
using namespace std;
/**
@@ -18,7 +19,7 @@
*/
void t_java_generator::init_generator() {
// Make output directory
- mkdir(get_out_dir().c_str(), S_IRWXU | S_IRWXG | S_IRWXO);
+ MKDIR(get_out_dir().c_str());
package_name_ = program_->get_java_package();
string dir = package_name_;
@@ -26,12 +27,12 @@
string::size_type loc;
while ((loc = dir.find(".")) != string::npos) {
subdir = subdir + "/" + dir.substr(0, loc);
- mkdir(subdir.c_str(), S_IRWXU | S_IRWXG | S_IRWXO);
+ MKDIR(subdir.c_str());
dir = dir.substr(loc+1);
}
if (dir.size() > 0) {
subdir = subdir + "/" + dir;
- mkdir(subdir.c_str(), S_IRWXU | S_IRWXG | S_IRWXO);
+ MKDIR(subdir.c_str());
}
package_dir_ = subdir;
@@ -565,7 +566,7 @@
indent() << "if (this." << (*f_iter)->get_name() << " != null) {" << endl;
indent_up();
}
- bool optional = bean_style_ && (*f_iter)->get_req() == t_field::OPTIONAL;
+ bool optional = bean_style_ && (*f_iter)->get_req() == t_field::T_OPTIONAL;
if (optional) {
out <<
indent() << "if (this.__isset." << (*f_iter)->get_name() << ") {" << endl;
diff --git a/compiler/cpp/src/generate/t_ocaml_generator.cc b/compiler/cpp/src/generate/t_ocaml_generator.cc
index 8bf6457..f4f5c4a 100644
--- a/compiler/cpp/src/generate/t_ocaml_generator.cc
+++ b/compiler/cpp/src/generate/t_ocaml_generator.cc
@@ -9,6 +9,7 @@
#include <sys/types.h>
#include <sstream>
#include "t_ocaml_generator.h"
+#include "platform.h"
using namespace std;
/*
@@ -72,7 +73,7 @@
*/
void t_ocaml_generator::init_generator() {
// Make output directory
- mkdir(get_out_dir().c_str(), S_IRWXU | S_IRWXG | S_IRWXO);
+ MKDIR(get_out_dir().c_str());
// Make output file
string f_types_name = get_out_dir()+program_name_+"_types.ml";
diff --git a/compiler/cpp/src/generate/t_perl_generator.cc b/compiler/cpp/src/generate/t_perl_generator.cc
index ee6b5b4..fe55418 100644
--- a/compiler/cpp/src/generate/t_perl_generator.cc
+++ b/compiler/cpp/src/generate/t_perl_generator.cc
@@ -8,6 +8,7 @@
#include <sys/stat.h>
#include <sstream>
#include "t_perl_generator.h"
+#include "platform.h"
using namespace std;
/**
@@ -18,13 +19,13 @@
*/
void t_perl_generator::init_generator() {
// Make output directory
- mkdir(get_out_dir().c_str(), S_IRWXU | S_IRWXG | S_IRWXO);
+ MKDIR(get_out_dir().c_str());
string outdir = get_out_dir();
std::string ns = program_->get_perl_package();
if (ns.length() > 0) {
outdir += ns + "/";
- mkdir(outdir.c_str(), S_IRWXU | S_IRWXG | S_IRWXO);
+ MKDIR(outdir.c_str());
}
// Make output file
diff --git a/compiler/cpp/src/generate/t_php_generator.cc b/compiler/cpp/src/generate/t_php_generator.cc
index 5b3c979..1f4ed1f 100644
--- a/compiler/cpp/src/generate/t_php_generator.cc
+++ b/compiler/cpp/src/generate/t_php_generator.cc
@@ -8,6 +8,7 @@
#include <sys/stat.h>
#include <sstream>
#include "t_php_generator.h"
+#include "platform.h"
using namespace std;
/**
@@ -18,7 +19,7 @@
*/
void t_php_generator::init_generator() {
// Make output directory
- mkdir(get_out_dir().c_str(), S_IRWXU | S_IRWXG | S_IRWXO);
+ MKDIR(get_out_dir().c_str());
// Make output file
string f_types_name = get_out_dir()+program_name_+"_types.php";
diff --git a/compiler/cpp/src/generate/t_py_generator.cc b/compiler/cpp/src/generate/t_py_generator.cc
index 7f3507f..ca192ce 100644
--- a/compiler/cpp/src/generate/t_py_generator.cc
+++ b/compiler/cpp/src/generate/t_py_generator.cc
@@ -10,6 +10,7 @@
#include <sstream>
#include <algorithm>
#include "t_py_generator.h"
+#include "platform.h"
using namespace std;
/**
@@ -24,7 +25,7 @@
package_dir_ = get_out_dir();
while (true) {
// TODO: Do better error checking here.
- mkdir(package_dir_.c_str(), S_IRWXU | S_IRWXG | S_IRWXO);
+ MKDIR(package_dir_.c_str());
std::ofstream init_py((package_dir_+"/__init__.py").c_str());
init_py.close();
if (module.empty()) {
@@ -1030,13 +1031,16 @@
// Make file executable, love that bitwise OR action
chmod(f_remote_name.c_str(),
- S_IRUSR |
- S_IWUSR |
- S_IXUSR |
- S_IRGRP |
- S_IXGRP |
- S_IROTH |
- S_IXOTH);
+ S_IRUSR
+ | S_IWUSR
+ | S_IXUSR
+#ifndef MINGW
+ | S_IRGRP
+ | S_IXGRP
+ | S_IROTH
+ | S_IXOTH
+#endif
+ );
}
/**
diff --git a/compiler/cpp/src/generate/t_rb_generator.cc b/compiler/cpp/src/generate/t_rb_generator.cc
index 59f25de..56690e8 100644
--- a/compiler/cpp/src/generate/t_rb_generator.cc
+++ b/compiler/cpp/src/generate/t_rb_generator.cc
@@ -9,6 +9,7 @@
#include <sys/types.h>
#include <sstream>
#include "t_rb_generator.h"
+#include "platform.h"
using namespace std;
/**
@@ -19,7 +20,7 @@
*/
void t_rb_generator::init_generator() {
// Make output directory
- mkdir(get_out_dir().c_str(), S_IRWXU | S_IRWXG | S_IRWXO);
+ MKDIR(get_out_dir().c_str());
// Make output file
string f_types_name = get_out_dir()+program_name_+"_types.rb";
diff --git a/compiler/cpp/src/generate/t_st_generator.cc b/compiler/cpp/src/generate/t_st_generator.cc
index c8456bc..fa7d851 100644
--- a/compiler/cpp/src/generate/t_st_generator.cc
+++ b/compiler/cpp/src/generate/t_st_generator.cc
@@ -11,6 +11,7 @@
#include <sys/types.h>
#include <sstream>
#include "t_st_generator.h"
+#include "platform.h"
using namespace std;
/**
@@ -21,7 +22,7 @@
*/
void t_st_generator::init_generator() {
// Make output directory
- mkdir(T_ST_DIR, S_IREAD | S_IWRITE | S_IEXEC);
+ MKDIR(T_ST_DIR);
temporary_var = 0;
@@ -560,7 +561,7 @@
indent_up();
for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
- bool optional = (*fld_iter)->get_req() == t_field::OPTIONAL;
+ bool optional = (*fld_iter)->get_req() == t_field::T_OPTIONAL;
string fname = (*fld_iter)->get_name();
string accessor = sname + " " + sanitize(fname);
diff --git a/compiler/cpp/src/generate/t_xsd_generator.cc b/compiler/cpp/src/generate/t_xsd_generator.cc
index 04645d2..7bab56d 100644
--- a/compiler/cpp/src/generate/t_xsd_generator.cc
+++ b/compiler/cpp/src/generate/t_xsd_generator.cc
@@ -8,11 +8,12 @@
#include <sys/stat.h>
#include <sstream>
#include "t_xsd_generator.h"
+#include "platform.h"
using namespace std;
void t_xsd_generator::init_generator() {
// Make output directory
- mkdir(get_out_dir().c_str(), S_IRWXU | S_IRWXG | S_IRWXO);
+ MKDIR(get_out_dir().c_str());
// Make output file
string f_php_name = get_out_dir()+program_->get_name()+"_xsd.php";
diff --git a/compiler/cpp/src/main.cc b/compiler/cpp/src/main.cc
index ac5fa04..4877431 100644
--- a/compiler/cpp/src/main.cc
+++ b/compiler/cpp/src/main.cc
@@ -23,6 +23,11 @@
#include <sys/stat.h>
#include <errno.h>
+#ifdef MINGW
+# include <windows.h> /* for GetFullPathName */
+# include <limits.h>
+#endif
+
// Careful: must include globals first for extern definitions
#include "globals.h"
@@ -155,6 +160,28 @@
bool gen_recurse = false;
/**
+ * MinGW doesn't have realpath, so use fallback implementation in that case,
+ * otherwise this just calls through to realpath
+ */
+char *saferealpath(const char *path, char *resolved_path) {
+#ifdef MINGW
+ char buf[MAX_PATH];
+ char* basename;
+ DWORD len = GetFullPathName(path, MAX_PATH, buf, &basename);
+ if (len == 0 || len > MAX_PATH - 1){
+ strcpy(resolved_path, path);
+ } else {
+ CharLowerBuff(buf, len);
+ strcpy(resolved_path, buf);
+ }
+ return resolved_path;
+#else
+ return realpath(path, resolved_path);
+#endif
+}
+
+
+/**
* Report an error to the user. This is called yyerror for historical
* reasons (lex and yacc expect the error reporting routine to be called
* this). Call this function to report any errors to the user.
@@ -276,7 +303,7 @@
if (filename[0] == '/') {
// Realpath!
char rp[PATH_MAX];
- if (realpath(filename.c_str(), rp) == NULL) {
+ if (saferealpath(filename.c_str(), rp) == NULL) {
pwarning(0, "Cannot open include file %s\n", filename.c_str());
return std::string();
}
@@ -298,7 +325,7 @@
// Realpath!
char rp[PATH_MAX];
- if (realpath(sfilename.c_str(), rp) == NULL) {
+ if (saferealpath(sfilename.c_str(), rp) == NULL) {
continue;
}
@@ -754,7 +781,7 @@
parse(*iter, program);
}
- // Parse the program the file
+ // Parse the program file
g_parse_mode = PROGRAM;
g_program = program;
g_scope = program->scope();
@@ -1011,6 +1038,16 @@
usage();
}
out_path = arg;
+
+#ifdef MINGW
+ //strip out trailing \ on Windows
+ int last = out_path.length()-1;
+ if (out_path[last] == '\\')
+ {
+ out_path.erase(last);
+ }
+#endif
+
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));
@@ -1038,8 +1075,8 @@
// Real-pathify it
char rp[PATH_MAX];
- if (realpath(argv[i], rp) == NULL) {
- failure("Could not open input file: %s", argv[i]);
+ if (saferealpath(argv[i], rp) == NULL) {
+ failure("Could not open input file with realpath: %s", argv[i]);
}
string input_file(rp);
diff --git a/compiler/cpp/src/parse/t_field.h b/compiler/cpp/src/parse/t_field.h
index 35ee1a2..fb882a9 100644
--- a/compiler/cpp/src/parse/t_field.h
+++ b/compiler/cpp/src/parse/t_field.h
@@ -34,7 +34,7 @@
type_(type),
name_(name),
key_(key),
- req_(OPT_IN_REQ_OUT),
+ req_(T_OPT_IN_REQ_OUT),
value_(NULL),
xsd_optional_(false),
xsd_nillable_(false),
@@ -55,9 +55,9 @@
}
enum e_req {
- REQUIRED,
- OPTIONAL,
- OPT_IN_REQ_OUT
+ T_REQUIRED,
+ T_OPTIONAL,
+ T_OPT_IN_REQ_OUT,
};
void set_req(e_req req) {
@@ -117,7 +117,7 @@
// but it does the same thing.
std::string get_fingerprint_material() const {
return boost::lexical_cast<std::string>(key_) + ":" +
- (req_ == OPTIONAL ? "opt-" : "") +
+ ((req_ == T_OPTIONAL) ? "opt-" : "") +
type_->get_fingerprint_material();
}
diff --git a/compiler/cpp/src/platform.h b/compiler/cpp/src/platform.h
new file mode 100644
index 0000000..df64e9a
--- /dev/null
+++ b/compiler/cpp/src/platform.h
@@ -0,0 +1,22 @@
+// Distributed under the Thrift Software License
+//
+// See accompanying file LICENSE or visit the Thrift site at:
+// http://developers.facebook.com/thrift/
+
+/**
+ * define for mkdir,since the method signature
+ * is different for the non-POSIX MinGW
+ */
+
+#ifdef MINGW
+#include <io.h>
+#else
+#include <sys/types.h>
+#include <sys/stat.h>
+#endif
+
+#if defined MINGW
+#define MKDIR(x) mkdir(x)
+#else
+#define MKDIR(x) mkdir(x, S_IRWXU | S_IRWXG | S_IRWXO)
+#endif
diff --git a/compiler/cpp/src/thrifty.yy b/compiler/cpp/src/thrifty.yy
index e46d0ef..9475adf 100644
--- a/compiler/cpp/src/thrifty.yy
+++ b/compiler/cpp/src/thrifty.yy
@@ -825,9 +825,9 @@
if (g_parse_mode == PROGRAM) {
pwarning(1, "required keyword is ignored in argument lists.\n");
}
- $$ = t_field::OPT_IN_REQ_OUT;
+ $$ = t_field::T_OPT_IN_REQ_OUT;
} else {
- $$ = t_field::REQUIRED;
+ $$ = t_field::T_REQUIRED;
}
}
| tok_optional
@@ -836,14 +836,14 @@
if (g_parse_mode == PROGRAM) {
pwarning(1, "optional keyword is ignored in argument lists.\n");
}
- $$ = t_field::OPT_IN_REQ_OUT;
+ $$ = t_field::T_OPT_IN_REQ_OUT;
} else {
- $$ = t_field::OPTIONAL;
+ $$ = t_field::T_OPTIONAL;
}
}
|
{
- $$ = t_field::OPT_IN_REQ_OUT;
+ $$ = t_field::T_OPT_IN_REQ_OUT;
}
FieldValue: