diff options
author | Paul Yang <paulyang1211@gmail.com> | 2015-03-09 06:49:58 +0800 |
---|---|---|
committer | Paul Yang <paulyang1211@gmail.com> | 2015-03-09 06:49:58 +0800 |
commit | a5f7bb8ebb60d636c21c18ad2ffeda80e8f80a48 (patch) | |
tree | 9297d18ba7a3888af43cdb21c0ad8bec5ec0adf9 /src/google/protobuf/compiler/command_line_interface.cc | |
parent | 88eda4d7760e43c2aca8285aeba76f5bb2d3deb3 (diff) | |
parent | eb2ce0293138532680fdd3647c01db7587b9367b (diff) | |
download | protobuf-a5f7bb8ebb60d636c21c18ad2ffeda80e8f80a48.tar.gz protobuf-a5f7bb8ebb60d636c21c18ad2ffeda80e8f80a48.tar.bz2 protobuf-a5f7bb8ebb60d636c21c18ad2ffeda80e8f80a48.zip |
Merge pull request #193 from TeBoring/sb
Implement a feature to generate a dependency file
Diffstat (limited to 'src/google/protobuf/compiler/command_line_interface.cc')
-rw-r--r-- | src/google/protobuf/compiler/command_line_interface.cc | 114 |
1 files changed, 112 insertions, 2 deletions
diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc index 09106313..567238ae 100644 --- a/src/google/protobuf/compiler/command_line_interface.cc +++ b/src/google/protobuf/compiler/command_line_interface.cc @@ -48,7 +48,6 @@ #include <iostream> #include <ctype.h> -#include <google/protobuf/stubs/hash.h> #include <memory> #ifndef _SHARED_PTR_H #include <google/protobuf/stubs/shared_ptr.h> @@ -255,6 +254,9 @@ class CommandLineInterface::GeneratorContextImpl : public GeneratorContext { // format, unless one has already been written. void AddJarManifest(); + // Get name of all output files. + void GetOutputFilenames(vector<string>* output_filenames); + // implements GeneratorContext -------------------------------------- io::ZeroCopyOutputStream* Open(const string& filename); io::ZeroCopyOutputStream* OpenForAppend(const string& filename); @@ -442,6 +444,14 @@ void CommandLineInterface::GeneratorContextImpl::AddJarManifest() { } } +void CommandLineInterface::GeneratorContextImpl::GetOutputFilenames( + vector<string>* output_filenames) { + for (map<string, string*>::iterator iter = files_.begin(); + iter != files_.end(); ++iter) { + output_filenames->push_back(iter->first); + } +} + io::ZeroCopyOutputStream* CommandLineInterface::GeneratorContextImpl::Open( const string& filename) { return new MemoryOutputStream(this, filename, false); @@ -673,7 +683,6 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) { // We construct a separate GeneratorContext for each output location. Note // that two code generators may output to the same location, in which case // they should share a single GeneratorContext so that OpenForInsert() works. - typedef hash_map<string, GeneratorContextImpl*> GeneratorContextMap; GeneratorContextMap output_directories; // Generate output. @@ -720,6 +729,13 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) { } } + if (!dependency_out_name_.empty()) { + if (!GenerateDependencyManifestFile(parsed_files, output_directories, + &source_tree)) { + return 1; + } + } + STLDeleteValues(&output_directories); if (!descriptor_set_name_.empty()) { @@ -778,6 +794,7 @@ void CommandLineInterface::Clear() { output_directives_.clear(); codec_type_.clear(); descriptor_set_name_.clear(); + dependency_out_name_.clear(); mode_ = MODE_COMPILE; print_mode_ = PRINT_NONE; @@ -880,6 +897,15 @@ CommandLineInterface::ParseArguments(int argc, const char* const argv[]) { std::cerr << "Missing output directives." << std::endl; return PARSE_ARGUMENT_FAIL; } + if (mode_ != MODE_COMPILE && !dependency_out_name_.empty()) { + cerr << "Can only use --dependency_out=FILE when generating code." << endl; + return PARSE_ARGUMENT_FAIL; + } + if (!dependency_out_name_.empty() && input_files_.size() > 1) { + cerr << "Can only process one input file when using --dependency_out=FILE." + << endl; + return PARSE_ARGUMENT_FAIL; + } if (imports_in_descriptor_set_ && descriptor_set_name_.empty()) { std::cerr << "--include_imports only makes sense when combined with " "--descriptor_set_out." << std::endl; @@ -1026,6 +1052,17 @@ CommandLineInterface::InterpretArgument(const string& name, } descriptor_set_name_ = value; + } else if (name == "--dependency_out") { + if (!dependency_out_name_.empty()) { + cerr << name << " may only be passed once." << endl; + return PARSE_ARGUMENT_FAIL; + } + if (value.empty()) { + cerr << name << " requires a non-empty value." << endl; + return PARSE_ARGUMENT_FAIL; + } + dependency_out_name_ = value; + } else if (name == "--include_imports") { if (imports_in_descriptor_set_) { std::cerr << name << " may only be passed once." << std::endl; @@ -1225,6 +1262,9 @@ void CommandLineInterface::PrintHelpText() { " include information about the original\n" " location of each decl in the source file as\n" " well as surrounding comments.\n" +" --dependency_out=FILE Write a dependency output file in the format\n" +" expected by make. This writes the transitive\n" +" set of input file paths to FILE\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).\n" @@ -1301,6 +1341,76 @@ bool CommandLineInterface::GenerateOutput( return true; } +bool CommandLineInterface::GenerateDependencyManifestFile( + const vector<const FileDescriptor*>& parsed_files, + const GeneratorContextMap& output_directories, + DiskSourceTree* source_tree) { + FileDescriptorSet file_set; + + set<const FileDescriptor*> already_seen; + for (int i = 0; i < parsed_files.size(); i++) { + GetTransitiveDependencies(parsed_files[i], + false, + &already_seen, + file_set.mutable_file()); + } + + vector<string> output_filenames; + for (GeneratorContextMap::const_iterator iter = output_directories.begin(); + iter != output_directories.end(); ++iter) { + const string& location = iter->first; + GeneratorContextImpl* directory = iter->second; + vector<string> relative_output_filenames; + directory->GetOutputFilenames(&relative_output_filenames); + for (int i = 0; i < relative_output_filenames.size(); i++) { + string output_filename = location + relative_output_filenames[i]; + if (output_filename.compare(0, 2, "./") == 0) { + output_filename = output_filename.substr(2); + } + output_filenames.push_back(output_filename); + } + } + + int fd; + do { + fd = open(dependency_out_name_.c_str(), + O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666); + } while (fd < 0 && errno == EINTR); + + if (fd < 0) { + perror(dependency_out_name_.c_str()); + return false; + } + + io::FileOutputStream out(fd); + io::Printer printer(&out, '$'); + + for (int i = 0; i < output_filenames.size(); i++) { + printer.Print(output_filenames[i].c_str()); + if (i == output_filenames.size() - 1) { + printer.Print(":"); + } else { + printer.Print(" \\\n"); + } + } + + for (int i = 0; i < file_set.file_size(); i++) { + const FileDescriptorProto& file = file_set.file(i); + const string& virtual_file = file.name(); + string disk_file; + if (source_tree && + source_tree->VirtualFileToDiskFile(virtual_file, &disk_file)) { + printer.Print(" $disk_file$", "disk_file", disk_file); + if (i < file_set.file_size() - 1) printer.Print("\\\n"); + } else { + cerr << "Unable to identify path for file " << virtual_file << endl; + return false; + } + } + + return true; +} + bool CommandLineInterface::GeneratePluginOutput( const vector<const FileDescriptor*>& parsed_files, const string& plugin_name, |