diff options
author | xiaofeng@google.com <xiaofeng@google.com@630680e5-0e50-0410-840e-4b1c322b438d> | 2012-09-22 02:40:50 +0000 |
---|---|---|
committer | xiaofeng@google.com <xiaofeng@google.com@630680e5-0e50-0410-840e-4b1c322b438d> | 2012-09-22 02:40:50 +0000 |
commit | b55a20fa2c669b181f47ea9219b8e74d1263da19 (patch) | |
tree | 3936a0e7c22196587a6d8397372de41434fe2129 /src/google/protobuf/compiler/command_line_interface.cc | |
parent | 9ced30caf94bb4e7e9629c199679ff44e8ca7389 (diff) | |
download | protobuf-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.cc | 232 |
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); + } } |