Просмотр исходного кода

Change target to output filenames

Bo Yang 10 лет назад
Родитель
Сommit
e2555e235f

+ 48 - 21
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>
@@ -254,6 +253,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);
@@ -441,6 +443,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);
@@ -670,7 +680,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.
@@ -717,16 +726,17 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) {
     }
   }
 
-  STLDeleteValues(&output_directories);
-
-  if (!descriptor_set_name_.empty()) {
-    if (!WriteDescriptorSet(parsed_files)) {
+  if (!dependency_out_name_.empty()) {
+    if (!GenerateDependencyManifestFile(parsed_files, output_directories,
+                                        &source_tree)) {
       return 1;
     }
   }
 
-  if (!dependency_out_name_.empty()) {
-    if (!GenerateDependencyManifestFile(parsed_files, &source_tree)) {
+  STLDeleteValues(&output_directories);
+
+  if (!descriptor_set_name_.empty()) {
+    if (!WriteDescriptorSet(parsed_files)) {
       return 1;
     }
   }
@@ -878,6 +888,15 @@ CommandLineInterface::ParseArguments(int argc, const char* const argv[]) {
     cerr << "Missing output directives." << 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()) {
     cerr << "--include_imports only makes sense when combined with "
             "--descriptor_set_out." << endl;
@@ -1028,11 +1047,6 @@ CommandLineInterface::InterpretArgument(const string& name,
       cerr << name << " requires a non-empty value." << endl;
       return PARSE_ARGUMENT_FAIL;
     }
-    if (mode_ != MODE_COMPILE) {
-      cerr << "Cannot use --encode or --decode and --dependency_out=FILE at "
-              "the same time." << endl;
-      return PARSE_ARGUMENT_FAIL;
-    }
     dependency_out_name_ = value;
 
   } else if (name == "--include_imports") {
@@ -1310,6 +1324,7 @@ bool CommandLineInterface::GenerateOutput(
 
 bool CommandLineInterface::GenerateDependencyManifestFile(
     const vector<const FileDescriptor*>& parsed_files,
+    const GeneratorContextMap& output_directories,
     DiskSourceTree* source_tree) {
   FileDescriptorSet file_set;
 
@@ -1321,6 +1336,18 @@ bool CommandLineInterface::GenerateDependencyManifestFile(
                               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++) {
+      output_filenames.push_back(location + relative_output_filenames[i]);
+    }
+  }
+
   int fd;
   do {
     fd = open(dependency_out_name_.c_str(),
@@ -1335,15 +1362,15 @@ bool CommandLineInterface::GenerateDependencyManifestFile(
   io::FileOutputStream out(fd);
   io::Printer printer(&out, '$');
 
-  if (dependency_out_name_.compare(0, 1, "/") != 0) {
-    // Convert relative path to absolute path before print.
-    printer.Print("$working_directory$/$output_filename$:",
-                  "working_directory", get_current_dir_name(),
-                  "output_filename", dependency_out_name_);
-  } else {
-    printer.Print("$output_filename$:",
-                  "output_filename", dependency_out_name_);
+  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();

+ 3 - 0
src/google/protobuf/compiler/command_line_interface.h

@@ -39,6 +39,7 @@
 #define GOOGLE_PROTOBUF_COMPILER_COMMAND_LINE_INTERFACE_H__
 
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/hash.h>
 #include <string>
 #include <vector>
 #include <map>
@@ -190,6 +191,7 @@ class LIBPROTOC_EXPORT CommandLineInterface {
   class ErrorPrinter;
   class GeneratorContextImpl;
   class MemoryOutputStream;
+  typedef hash_map<string, GeneratorContextImpl*> GeneratorContextMap;
 
   // Clear state from previous Run().
   void Clear();
@@ -250,6 +252,7 @@ class LIBPROTOC_EXPORT CommandLineInterface {
   // Implements the --dependency_out option
   bool GenerateDependencyManifestFile(
       const vector<const FileDescriptor*>& parsed_files,
+      const GeneratorContextMap& output_directories,
       DiskSourceTree* source_tree);
 
   // Get all transitive dependencies of the given file (including the file

+ 22 - 4
src/google/protobuf/compiler/command_line_interface_unittest.cc

@@ -959,6 +959,24 @@ TEST_F(CommandLineInterfaceTest, WriteTransitiveDescriptorSetWithSourceInfo) {
   EXPECT_TRUE(descriptor_set.file(1).has_source_code_info());
 }
 
+TEST_F(CommandLineInterfaceTest, WriteDependencyManifestFileGivenTwoInputs) {
+  CreateTempFile("foo.proto",
+    "syntax = \"proto2\";\n"
+    "message Foo {}\n");
+  CreateTempFile("bar.proto",
+    "syntax = \"proto2\";\n"
+    "import \"foo.proto\";\n"
+    "message Bar {\n"
+    "  optional Foo foo = 1;\n"
+    "}\n");
+
+  Run("protocol_compiler --dependency_out=$tmpdir/manifest "
+      "--test_out=$tmpdir --proto_path=$tmpdir bar.proto foo.proto");
+
+  ExpectErrorText(
+      "Can only process one input file when using --dependency_out=FILE.\n");
+}
+
 TEST_F(CommandLineInterfaceTest, WriteDependencyManifestFile) {
   CreateTempFile("foo.proto",
     "syntax = \"proto2\";\n"
@@ -976,8 +994,8 @@ TEST_F(CommandLineInterfaceTest, WriteDependencyManifestFile) {
   ExpectNoErrors();
 
   ExpectFileContent("manifest",
-                    "$tmpdir/manifest: $tmpdir/foo.proto\\\n"
-                    " $tmpdir/bar.proto");
+                    "$tmpdir/bar.proto.MockCodeGenerator.test_generator: "
+                    "$tmpdir/foo.proto\\\n $tmpdir/bar.proto");
 }
 
 TEST_F(CommandLineInterfaceTest, WriteDependencyManifestFileForRelativePath) {
@@ -1000,8 +1018,8 @@ TEST_F(CommandLineInterfaceTest, WriteDependencyManifestFileForRelativePath) {
   ExpectNoErrors();
 
   ExpectFileContent("manifest",
-                    "$tmpdir/manifest: $tmpdir/foo.proto\\\n"
-                    " $tmpdir/bar.proto");
+                    "$tmpdir/bar.proto.MockCodeGenerator.test_generator: "
+                    "$tmpdir/foo.proto\\\n $tmpdir/bar.proto");
 
   File::ChangeWorkingDirectory(current_working_directory);
 }