aboutsummaryrefslogtreecommitdiff
path: root/src/google/protobuf/compiler/command_line_interface.cc
diff options
context:
space:
mode:
authorxiaofeng@google.com <xiaofeng@google.com@630680e5-0e50-0410-840e-4b1c322b438d>2012-09-22 02:40:50 +0000
committerxiaofeng@google.com <xiaofeng@google.com@630680e5-0e50-0410-840e-4b1c322b438d>2012-09-22 02:40:50 +0000
commitb55a20fa2c669b181f47ea9219b8e74d1263da19 (patch)
tree3936a0e7c22196587a6d8397372de41434fe2129 /src/google/protobuf/compiler/command_line_interface.cc
parent9ced30caf94bb4e7e9629c199679ff44e8ca7389 (diff)
downloadprotobuf-b55a20fa2c669b181f47ea9219b8e74d1263da19.tar.gz
protobuf-b55a20fa2c669b181f47ea9219b8e74d1263da19.tar.bz2
protobuf-b55a20fa2c669b181f47ea9219b8e74d1263da19.zip
Down-integrate from internal branch
Diffstat (limited to 'src/google/protobuf/compiler/command_line_interface.cc')
-rw-r--r--src/google/protobuf/compiler/command_line_interface.cc232
1 files changed, 156 insertions, 76 deletions
diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc
index 1c76994b..8dac5f42 100644
--- a/src/google/protobuf/compiler/command_line_interface.cc
+++ b/src/google/protobuf/compiler/command_line_interface.cc
@@ -59,12 +59,13 @@
#include <google/protobuf/descriptor.h>
#include <google/protobuf/text_format.h>
#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/substitute.h>
#include <google/protobuf/stubs/map-util.h>
-#include <google/protobuf/stubs/stl_util-inl.h>
+#include <google/protobuf/stubs/stl_util.h>
namespace google {
@@ -145,7 +146,7 @@ void AddTrailingSlash(string* path) {
bool VerifyDirectoryExists(const string& path) {
if (path.empty()) return true;
- if (access(path.c_str(), W_OK) == -1) {
+ if (access(path.c_str(), F_OK) == -1) {
cerr << path << ": " << strerror(errno) << endl;
return false;
} else {
@@ -566,6 +567,7 @@ CommandLineInterface::CommandLineInterface()
: mode_(MODE_COMPILE),
error_format_(ERROR_FORMAT_GCC),
imports_in_descriptor_set_(false),
+ source_info_in_descriptor_set_(false),
disallow_services_(false),
inputs_are_proto_path_relative_(false) {}
CommandLineInterface::~CommandLineInterface() {}
@@ -574,9 +576,23 @@ void CommandLineInterface::RegisterGenerator(const string& flag_name,
CodeGenerator* generator,
const string& help_text) {
GeneratorInfo info;
+ info.flag_name = flag_name;
info.generator = generator;
info.help_text = help_text;
- generators_[flag_name] = info;
+ generators_by_flag_name_[flag_name] = info;
+}
+
+void CommandLineInterface::RegisterGenerator(const string& flag_name,
+ const string& option_flag_name,
+ CodeGenerator* generator,
+ const string& help_text) {
+ GeneratorInfo info;
+ info.flag_name = flag_name;
+ info.option_flag_name = option_flag_name;
+ info.generator = generator;
+ info.help_text = help_text;
+ generators_by_flag_name_[flag_name] = info;
+ generators_by_option_name_[option_flag_name] = info;
}
void CommandLineInterface::AllowPlugins(const string& exe_name_prefix) {
@@ -585,7 +601,14 @@ void CommandLineInterface::AllowPlugins(const string& exe_name_prefix) {
int CommandLineInterface::Run(int argc, const char* const argv[]) {
Clear();
- if (!ParseArguments(argc, argv)) return 1;
+ switch (ParseArguments(argc, argv)) {
+ case PARSE_ARGUMENT_DONE_AND_EXIT:
+ return 0;
+ case PARSE_ARGUMENT_FAIL:
+ return 1;
+ case PARSE_ARGUMENT_DONE_AND_CONTINUE:
+ break;
+ }
// Set up the source tree.
DiskSourceTree source_tree;
@@ -713,6 +736,7 @@ void CommandLineInterface::Clear() {
mode_ = MODE_COMPILE;
imports_in_descriptor_set_ = false;
+ source_info_in_descriptor_set_ = false;
disallow_services_ = false;
}
@@ -755,7 +779,8 @@ bool CommandLineInterface::MakeInputsBeProtoPathRelative(
return true;
}
-bool CommandLineInterface::ParseArguments(int argc, const char* const argv[]) {
+CommandLineInterface::ParseArgumentStatus
+CommandLineInterface::ParseArguments(int argc, const char* const argv[]) {
executable_name_ = argv[0];
// Iterate through all arguments and parse them.
@@ -769,41 +794,50 @@ bool CommandLineInterface::ParseArguments(int argc, const char* const argv[]) {
if (name == "--decode") {
cerr << "To decode an unknown message, use --decode_raw." << endl;
}
- return false;
+ return PARSE_ARGUMENT_FAIL;
} else {
++i;
value = argv[i];
}
}
- if (!InterpretArgument(name, value)) return false;
+ ParseArgumentStatus status = InterpretArgument(name, value);
+ if (status != PARSE_ARGUMENT_DONE_AND_CONTINUE)
+ return status;
}
// If no --proto_path was given, use the current working directory.
if (proto_path_.empty()) {
- proto_path_.push_back(make_pair<string, string>("", "."));
+ // Don't use make_pair as the old/default standard library on Solaris
+ // doesn't support it without explicit template parameters, which are
+ // incompatible with C++0x's make_pair.
+ proto_path_.push_back(pair<string, string>("", "."));
}
// Check some errror cases.
bool decoding_raw = (mode_ == MODE_DECODE) && codec_type_.empty();
if (decoding_raw && !input_files_.empty()) {
cerr << "When using --decode_raw, no input files should be given." << endl;
- return false;
+ return PARSE_ARGUMENT_FAIL;
} else if (!decoding_raw && input_files_.empty()) {
cerr << "Missing input file." << endl;
- return false;
+ return PARSE_ARGUMENT_FAIL;
}
if (mode_ == MODE_COMPILE && output_directives_.empty() &&
descriptor_set_name_.empty()) {
cerr << "Missing output directives." << endl;
- return false;
+ return PARSE_ARGUMENT_FAIL;
}
if (imports_in_descriptor_set_ && descriptor_set_name_.empty()) {
cerr << "--include_imports only makes sense when combined with "
"--descriptor_set_out." << endl;
}
+ if (source_info_in_descriptor_set_ && descriptor_set_name_.empty()) {
+ cerr << "--include_source_info only makes sense when combined with "
+ "--descriptor_set_out." << endl;
+ }
- return true;
+ return PARSE_ARGUMENT_DONE_AND_CONTINUE;
}
bool CommandLineInterface::ParseArgument(const char* arg,
@@ -853,6 +887,7 @@ bool CommandLineInterface::ParseArgument(const char* arg,
if (*name == "-h" || *name == "--help" ||
*name == "--disallow_services" ||
*name == "--include_imports" ||
+ *name == "--include_source_info" ||
*name == "--version" ||
*name == "--decode_raw") {
// HACK: These are the only flags that don't take a value.
@@ -865,8 +900,9 @@ bool CommandLineInterface::ParseArgument(const char* arg,
return true;
}
-bool CommandLineInterface::InterpretArgument(const string& name,
- const string& value) {
+CommandLineInterface::ParseArgumentStatus
+CommandLineInterface::InterpretArgument(const string& name,
+ const string& value) {
if (name.empty()) {
// Not a flag. Just a filename.
if (value.empty()) {
@@ -874,7 +910,7 @@ bool CommandLineInterface::InterpretArgument(const string& name,
"arguments to " << executable_name_ << ". This is actually "
"sort of hard to do. Congrats. Unfortunately it is not valid "
"input so the program is going to die now." << endl;
- return false;
+ return PARSE_ARGUMENT_FAIL;
}
input_files_.push_back(value);
@@ -902,7 +938,7 @@ bool CommandLineInterface::InterpretArgument(const string& name,
if (disk_path.empty()) {
cerr << "--proto_path passed empty directory name. (Use \".\" for "
"current directory.)" << endl;
- return false;
+ return PARSE_ARGUMENT_FAIL;
}
// Make sure disk path exists, warn otherwise.
@@ -910,35 +946,45 @@ bool CommandLineInterface::InterpretArgument(const string& name,
cerr << disk_path << ": warning: directory does not exist." << endl;
}
- proto_path_.push_back(make_pair<string, string>(virtual_path, disk_path));
+ // Don't use make_pair as the old/default standard library on Solaris
+ // doesn't support it without explicit template parameters, which are
+ // incompatible with C++0x's make_pair.
+ proto_path_.push_back(pair<string, string>(virtual_path, disk_path));
}
} else if (name == "-o" || name == "--descriptor_set_out") {
if (!descriptor_set_name_.empty()) {
cerr << name << " may only be passed once." << endl;
- return false;
+ return PARSE_ARGUMENT_FAIL;
}
if (value.empty()) {
cerr << name << " requires a non-empty value." << endl;
- return false;
+ return PARSE_ARGUMENT_FAIL;
}
if (mode_ != MODE_COMPILE) {
cerr << "Cannot use --encode or --decode and generate descriptors at the "
"same time." << endl;
- return false;
+ return PARSE_ARGUMENT_FAIL;
}
descriptor_set_name_ = value;
} else if (name == "--include_imports") {
if (imports_in_descriptor_set_) {
cerr << name << " may only be passed once." << endl;
- return false;
+ return PARSE_ARGUMENT_FAIL;
}
imports_in_descriptor_set_ = true;
+ } else if (name == "--include_source_info") {
+ if (source_info_in_descriptor_set_) {
+ cerr << name << " may only be passed once." << endl;
+ return PARSE_ARGUMENT_FAIL;
+ }
+ source_info_in_descriptor_set_ = true;
+
} else if (name == "-h" || name == "--help") {
PrintHelpText();
- return false; // Exit without running compiler.
+ return PARSE_ARGUMENT_DONE_AND_EXIT; // Exit without running compiler.
} else if (name == "--version") {
if (!version_info_.empty()) {
@@ -947,7 +993,7 @@ bool CommandLineInterface::InterpretArgument(const string& name,
cout << "libprotoc "
<< protobuf::internal::VersionString(GOOGLE_PROTOBUF_VERSION)
<< endl;
- return false; // Exit without running compiler.
+ return PARSE_ARGUMENT_DONE_AND_EXIT; // Exit without running compiler.
} else if (name == "--disallow_services") {
disallow_services_ = true;
@@ -956,12 +1002,12 @@ bool CommandLineInterface::InterpretArgument(const string& name,
name == "--decode_raw") {
if (mode_ != MODE_COMPILE) {
cerr << "Only one of --encode and --decode can be specified." << endl;
- return false;
+ return PARSE_ARGUMENT_FAIL;
}
if (!output_directives_.empty() || !descriptor_set_name_.empty()) {
cerr << "Cannot use " << name
<< " and generate code or descriptors at the same time." << endl;
- return false;
+ return PARSE_ARGUMENT_FAIL;
}
mode_ = (name == "--encode") ? MODE_ENCODE : MODE_DECODE;
@@ -971,10 +1017,10 @@ bool CommandLineInterface::InterpretArgument(const string& name,
if (name == "--decode") {
cerr << "To decode an unknown message, use --decode_raw." << endl;
}
- return false;
+ return PARSE_ARGUMENT_FAIL;
} else if (!value.empty() && name == "--decode_raw") {
cerr << "--decode_raw does not take a parameter." << endl;
- return false;
+ return PARSE_ARGUMENT_FAIL;
}
codec_type_ = value;
@@ -986,16 +1032,16 @@ bool CommandLineInterface::InterpretArgument(const string& name,
error_format_ = ERROR_FORMAT_MSVS;
} else {
cerr << "Unknown error format: " << value << endl;
- return false;
+ return PARSE_ARGUMENT_FAIL;
}
} else if (name == "--plugin") {
if (plugin_prefix_.empty()) {
cerr << "This compiler does not support plugins." << endl;
- return false;
+ return PARSE_ARGUMENT_FAIL;
}
- string name;
+ string plugin_name;
string path;
string::size_type equals_pos = value.find_first_of('=');
@@ -1003,57 +1049,68 @@ bool CommandLineInterface::InterpretArgument(const string& name,
// Use the basename of the file.
string::size_type slash_pos = value.find_last_of('/');
if (slash_pos == string::npos) {
- name = value;
+ plugin_name = value;
} else {
- name = value.substr(slash_pos + 1);
+ plugin_name = value.substr(slash_pos + 1);
}
path = value;
} else {
- name = value.substr(0, equals_pos);
+ plugin_name = value.substr(0, equals_pos);
path = value.substr(equals_pos + 1);
}
- plugins_[name] = path;
+ plugins_[plugin_name] = path;
} else {
// Some other flag. Look it up in the generators list.
- const GeneratorInfo* generator_info = FindOrNull(generators_, name);
+ const GeneratorInfo* generator_info =
+ FindOrNull(generators_by_flag_name_, name);
if (generator_info == NULL &&
(plugin_prefix_.empty() || !HasSuffixString(name, "_out"))) {
- cerr << "Unknown flag: " << name << endl;
- return false;
- }
+ // Check if it's a generator option flag.
+ generator_info = FindOrNull(generators_by_option_name_, name);
+ if (generator_info == NULL) {
+ cerr << "Unknown flag: " << name << endl;
+ return PARSE_ARGUMENT_FAIL;
+ } else {
+ string* parameters = &generator_parameters_[generator_info->flag_name];
+ if (!parameters->empty()) {
+ parameters->append(",");
+ }
+ parameters->append(value);
+ }
+ } else {
+ // It's an output flag. Add it to the output directives.
+ if (mode_ != MODE_COMPILE) {
+ cerr << "Cannot use --encode or --decode and generate code at the "
+ "same time." << endl;
+ return PARSE_ARGUMENT_FAIL;
+ }
- // It's an output flag. Add it to the output directives.
- if (mode_ != MODE_COMPILE) {
- cerr << "Cannot use --encode or --decode and generate code at the "
- "same time." << endl;
- return false;
- }
+ OutputDirective directive;
+ directive.name = name;
+ if (generator_info == NULL) {
+ directive.generator = NULL;
+ } else {
+ directive.generator = generator_info->generator;
+ }
- OutputDirective directive;
- directive.name = name;
- if (generator_info == NULL) {
- directive.generator = NULL;
- } else {
- directive.generator = generator_info->generator;
- }
+ // Split value at ':' to separate the generator parameter from the
+ // filename. However, avoid doing this if the colon is part of a valid
+ // Windows-style absolute path.
+ string::size_type colon_pos = value.find_first_of(':');
+ if (colon_pos == string::npos || IsWindowsAbsolutePath(value)) {
+ directive.output_location = value;
+ } else {
+ directive.parameter = value.substr(0, colon_pos);
+ directive.output_location = value.substr(colon_pos + 1);
+ }
- // Split value at ':' to separate the generator parameter from the
- // filename. However, avoid doing this if the colon is part of a valid
- // Windows-style absolute path.
- string::size_type colon_pos = value.find_first_of(':');
- if (colon_pos == string::npos || IsWindowsAbsolutePath(value)) {
- directive.output_location = value;
- } else {
- directive.parameter = value.substr(0, colon_pos);
- directive.output_location = value.substr(colon_pos + 1);
+ output_directives_.push_back(directive);
}
-
- output_directives_.push_back(directive);
}
- return true;
+ return PARSE_ARGUMENT_DONE_AND_CONTINUE;
}
void CommandLineInterface::PrintHelpText() {
@@ -1086,6 +1143,12 @@ void CommandLineInterface::PrintHelpText() {
" --include_imports When using --descriptor_set_out, also include\n"
" all dependencies of the input files in the\n"
" set, so that the set is self-contained.\n"
+" --include_source_info When using --descriptor_set_out, do not strip\n"
+" SourceCodeInfo from the FileDescriptorProto.\n"
+" This results in vastly larger descriptors that\n"
+" include information about the original\n"
+" location of each decl in the source file as\n"
+" well as surrounding comments.\n"
" --error_format=FORMAT Set the format in which to print errors.\n"
" FORMAT may be 'gcc' (the default) or 'msvs'\n"
" (Microsoft Visual Studio format)." << endl;
@@ -1101,8 +1164,8 @@ void CommandLineInterface::PrintHelpText() {
" the executable's own name differs." << endl;
}
- for (GeneratorMap::iterator iter = generators_.begin();
- iter != generators_.end(); ++iter) {
+ for (GeneratorMap::iterator iter = generators_by_flag_name_.begin();
+ iter != generators_by_flag_name_.end(); ++iter) {
// FIXME(kenton): If the text is long enough it will wrap, which is ugly,
// but fixing this nicely (e.g. splitting on spaces) is probably more
// trouble than it's worth.
@@ -1136,10 +1199,16 @@ bool CommandLineInterface::GenerateOutput(
}
} else {
// Regular generator.
+ string parameters = output_directive.parameter;
+ if (!generator_parameters_[output_directive.name].empty()) {
+ if (!parameters.empty()) {
+ parameters.append(",");
+ }
+ parameters.append(generator_parameters_[output_directive.name]);
+ }
for (int i = 0; i < parsed_files.size(); i++) {
- if (!output_directive.generator->Generate(
- parsed_files[i], output_directive.parameter,
- generator_context, &error)) {
+ if (!output_directive.generator->Generate(parsed_files[i], parameters,
+ generator_context, &error)) {
// Generator returned an error.
cerr << output_directive.name << ": " << parsed_files[i]->name() << ": "
<< error << endl;
@@ -1168,8 +1237,9 @@ bool CommandLineInterface::GeneratePluginOutput(
set<const FileDescriptor*> already_seen;
for (int i = 0; i < parsed_files.size(); i++) {
request.add_file_to_generate(parsed_files[i]->name());
- GetTransitiveDependencies(parsed_files[i], &already_seen,
- request.mutable_proto_file());
+ GetTransitiveDependencies(parsed_files[i],
+ true, // Include source code info.
+ &already_seen, request.mutable_proto_file());
}
// Invoke the plugin.
@@ -1299,12 +1369,17 @@ bool CommandLineInterface::WriteDescriptorSet(
if (imports_in_descriptor_set_) {
set<const FileDescriptor*> already_seen;
for (int i = 0; i < parsed_files.size(); i++) {
- GetTransitiveDependencies(
- parsed_files[i], &already_seen, file_set.mutable_file());
+ GetTransitiveDependencies(parsed_files[i],
+ source_info_in_descriptor_set_,
+ &already_seen, file_set.mutable_file());
}
} else {
for (int i = 0; i < parsed_files.size(); i++) {
- parsed_files[i]->CopyTo(file_set.add_file());
+ FileDescriptorProto* file_proto = file_set.add_file();
+ parsed_files[i]->CopyTo(file_proto);
+ if (source_info_in_descriptor_set_) {
+ parsed_files[i]->CopySourceCodeInfoTo(file_proto);
+ }
}
}
@@ -1334,7 +1409,7 @@ bool CommandLineInterface::WriteDescriptorSet(
}
void CommandLineInterface::GetTransitiveDependencies(
- const FileDescriptor* file,
+ const FileDescriptor* file, bool include_source_code_info,
set<const FileDescriptor*>* already_seen,
RepeatedPtrField<FileDescriptorProto>* output) {
if (!already_seen->insert(file).second) {
@@ -1344,11 +1419,16 @@ void CommandLineInterface::GetTransitiveDependencies(
// Add all dependencies.
for (int i = 0; i < file->dependency_count(); i++) {
- GetTransitiveDependencies(file->dependency(i), already_seen, output);
+ GetTransitiveDependencies(file->dependency(i), include_source_code_info,
+ already_seen, output);
}
// Add this file.
- file->CopyTo(output->Add());
+ FileDescriptorProto* new_descriptor = output->Add();
+ file->CopyTo(new_descriptor);
+ if (include_source_code_info) {
+ file->CopySourceCodeInfoTo(new_descriptor);
+ }
}