in thrift/compiler/compiler.cc [140:300]
std::string parseArgs(
const std::vector<std::string>& arguments,
parsing_params& pparams,
gen_params& gparams,
diagnostic_params& dparams) {
// Check for necessary arguments, you gotta have at least a filename and
// an output language flag.
if (arguments.size() < 2) {
usage();
return {};
}
// A helper that grabs the next argument, if possible.
// Outputs an error and returns nullptr if not.
size_t arg_i = 1; // Skip the binary name.
auto consume_arg = [&](const char* arg_name) -> const std::string* {
// Note: The input filename must be the last argument.
if (arg_i + 2 >= arguments.size()) {
fprintf(
stderr,
"!!! Missing %s between %s and '%s'\n",
arg_name,
arguments[arg_i].c_str(),
arguments[arg_i + 1].c_str());
usage();
return nullptr;
}
return &arguments[++arg_i];
};
// Hacky parameter handling... I didn't feel like using a library sorry!
bool nowarn = false; // Guard so --nowarn and --strict are order agnostic.
for (; arg_i < arguments.size() - 1;
++arg_i) { // Last argument is the src file.
// Parse flag.
std::string flag;
if (arguments[arg_i].size() < 2 || arguments[arg_i][0] != '-') {
fprintf(stderr, "!!! Expected flag, got: %s\n", arguments[arg_i].c_str());
usage();
return {};
} else if (arguments[arg_i][1] == '-') {
flag = arguments[arg_i].substr(2);
} else {
flag = arguments[arg_i].substr(1);
}
// Interpret flag.
if (flag == "allow-experimental-features") {
auto* arg = consume_arg("feature");
if (arg == nullptr) {
return {};
}
boost::algorithm::split(
pparams.allow_experimental_features, *arg, isComma);
} else if (flag == "debug") {
dparams.debug = true;
g_debug = 1;
} else if (flag == "nowarn") {
dparams.warn_level = g_warn = 0;
nowarn = true;
} else if (flag == "strict") {
pparams.strict = 255;
if (!nowarn) { // Don't override nowarn.
dparams.warn_level = g_warn = 2;
}
} else if (flag == "v" || flag == "verbose") {
dparams.info = true;
g_verbose = 1;
} else if (flag == "r" || flag == "recurse") {
gparams.gen_recurse = true;
} else if (flag == "allow-neg-keys") {
pparams.allow_neg_field_keys = true;
} else if (flag == "allow-neg-enum-vals") {
dparams.allow_neg_enum_vals = true;
} else if (flag == "allow-64bit-consts") {
pparams.allow_64bit_consts = true;
} else if (flag == "record-genfiles") {
auto* arg = consume_arg("genfile file specification");
if (arg == nullptr) {
return {};
}
gparams.genfile = *arg;
} else if (flag == "gen") {
auto* arg = consume_arg("generator specification");
if (arg == nullptr) {
return {};
}
gparams.targets.push_back(*arg);
} else if (flag == "cpp_use_include_prefix") {
g_cpp_use_include_prefix = true;
} else if (flag == "I") {
auto* arg = consume_arg("include directory");
if (arg == nullptr) {
return {};
}
// An argument of "-I\ asdf" is invalid and has unknown results
pparams.incl_searchpath.push_back(*arg);
} else if (flag == "o" || flag == "out") {
auto* arg = consume_arg("output directory");
if (arg == nullptr) {
return {};
}
std::string out_path = *arg;
bool out_path_is_absolute = (flag == "out");
// Strip out trailing \ on a Windows path
if (platform_is_windows()) {
int last = out_path.length() - 1;
if (out_path[last] == '\\') {
out_path.erase(last);
}
}
if (out_path_is_absolute) {
// Invoker specified `-out blah`. We are supposed to output directly
// into blah, e.g. `blah/Foo.java`. Make the directory if necessary,
// just like how for `-o blah` we make `o/gen-java`
boost::system::error_code errc;
boost::filesystem::create_directory(out_path, errc);
if (errc) {
fprintf(
stderr,
"Output path %s is unusable or not a directory\n",
out_path.c_str());
return {};
}
}
if (!boost::filesystem::is_directory(out_path)) {
fprintf(
stderr,
"Output path %s is unusable or not a directory\n",
out_path.c_str());
return {};
}
gparams.context = {std::move(out_path), out_path_is_absolute};
} else {
fprintf(
stderr, "!!! Unrecognized option: %s\n", arguments[arg_i].c_str());
usage();
return {};
}
}
if (const char* env_p = std::getenv("THRIFT_INCLUDE_PATH")) {
std::vector<std::string> components;
boost::algorithm::split(components, env_p, isPathSeparator);
pparams.incl_searchpath.insert(
pparams.incl_searchpath.end(), components.begin(), components.end());
}
// You gotta generate something!
if (gparams.targets.empty()) {
fprintf(stderr, "!!! No output language(s) specified\n\n");
usage();
return {};
}
// Return the input file name.
assert(arg_i == arguments.size() - 1);
return arguments[arg_i];
}