Home | History | Annotate | Download | only in compiler
      1 // Protocol Buffers - Google's data interchange format
      2 // Copyright 2008 Google Inc.  All rights reserved.
      3 // https://developers.google.com/protocol-buffers/
      4 //
      5 // Redistribution and use in source and binary forms, with or without
      6 // modification, are permitted provided that the following conditions are
      7 // met:
      8 //
      9 //     * Redistributions of source code must retain the above copyright
     10 // notice, this list of conditions and the following disclaimer.
     11 //     * Redistributions in binary form must reproduce the above
     12 // copyright notice, this list of conditions and the following disclaimer
     13 // in the documentation and/or other materials provided with the
     14 // distribution.
     15 //     * Neither the name of Google Inc. nor the names of its
     16 // contributors may be used to endorse or promote products derived from
     17 // this software without specific prior written permission.
     18 //
     19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30 
     31 // Author: kenton (at) google.com (Kenton Varda)
     32 
     33 #include <google/protobuf/compiler/plugin.h>
     34 
     35 #include <iostream>
     36 #include <set>
     37 
     38 #ifdef _WIN32
     39 #include <io.h>
     40 #include <fcntl.h>
     41 #ifndef STDIN_FILENO
     42 #define STDIN_FILENO 0
     43 #endif
     44 #ifndef STDOUT_FILENO
     45 #define STDOUT_FILENO 1
     46 #endif
     47 #else
     48 #include <unistd.h>
     49 #endif
     50 
     51 #include <google/protobuf/stubs/logging.h>
     52 #include <google/protobuf/stubs/common.h>
     53 #include <google/protobuf/compiler/plugin.pb.h>
     54 #include <google/protobuf/compiler/code_generator.h>
     55 #include <google/protobuf/descriptor.h>
     56 #include <google/protobuf/io/zero_copy_stream_impl.h>
     57 
     58 
     59 namespace google {
     60 namespace protobuf {
     61 namespace compiler {
     62 
     63 class GeneratorResponseContext : public GeneratorContext {
     64  public:
     65   GeneratorResponseContext(CodeGeneratorResponse* response,
     66                            const vector<const FileDescriptor*>& parsed_files)
     67       : response_(response),
     68         parsed_files_(parsed_files) {}
     69   virtual ~GeneratorResponseContext() {}
     70 
     71   // implements GeneratorContext --------------------------------------
     72 
     73   virtual io::ZeroCopyOutputStream* Open(const string& filename) {
     74     CodeGeneratorResponse::File* file = response_->add_file();
     75     file->set_name(filename);
     76     return new io::StringOutputStream(file->mutable_content());
     77   }
     78 
     79   virtual io::ZeroCopyOutputStream* OpenForInsert(
     80       const string& filename, const string& insertion_point) {
     81     CodeGeneratorResponse::File* file = response_->add_file();
     82     file->set_name(filename);
     83     file->set_insertion_point(insertion_point);
     84     return new io::StringOutputStream(file->mutable_content());
     85   }
     86 
     87   void ListParsedFiles(vector<const FileDescriptor*>* output) {
     88     *output = parsed_files_;
     89   }
     90 
     91  private:
     92   CodeGeneratorResponse* response_;
     93   const vector<const FileDescriptor*>& parsed_files_;
     94 };
     95 
     96 bool GenerateCode(const CodeGeneratorRequest& request,
     97     const CodeGenerator& generator, CodeGeneratorResponse* response,
     98     string* error_msg) {
     99   DescriptorPool pool;
    100   for (int i = 0; i < request.proto_file_size(); i++) {
    101     const FileDescriptor* file = pool.BuildFile(request.proto_file(i));
    102     if (file == NULL) {
    103       // BuildFile() already wrote an error message.
    104       return false;
    105     }
    106   }
    107 
    108   vector<const FileDescriptor*> parsed_files;
    109   for (int i = 0; i < request.file_to_generate_size(); i++) {
    110     parsed_files.push_back(pool.FindFileByName(request.file_to_generate(i)));
    111     if (parsed_files.back() == NULL) {
    112       *error_msg = "protoc asked plugin to generate a file but "
    113                    "did not provide a descriptor for the file: " +
    114                    request.file_to_generate(i);
    115       return false;
    116     }
    117   }
    118 
    119   GeneratorResponseContext context(response, parsed_files);
    120 
    121   if (generator.HasGenerateAll()) {
    122     string error;
    123     bool succeeded = generator.GenerateAll(
    124         parsed_files, request.parameter(), &context, &error);
    125 
    126     if (!succeeded && error.empty()) {
    127       error = "Code generator returned false but provided no error "
    128               "description.";
    129     }
    130     if (!error.empty()) {
    131       response->set_error(error);
    132     }
    133   } else {
    134     for (int i = 0; i < parsed_files.size(); i++) {
    135       const FileDescriptor* file = parsed_files[i];
    136 
    137       string error;
    138       bool succeeded = generator.Generate(
    139           file, request.parameter(), &context, &error);
    140 
    141       if (!succeeded && error.empty()) {
    142         error = "Code generator returned false but provided no error "
    143                 "description.";
    144       }
    145       if (!error.empty()) {
    146         response->set_error(file->name() + ": " + error);
    147         break;
    148       }
    149     }
    150   }
    151 
    152   return true;
    153 }
    154 
    155 int PluginMain(int argc, char* argv[], const CodeGenerator* generator) {
    156 
    157   if (argc > 1) {
    158     std::cerr << argv[0] << ": Unknown option: " << argv[1] << std::endl;
    159     return 1;
    160   }
    161 
    162 #ifdef _WIN32
    163   _setmode(STDIN_FILENO, _O_BINARY);
    164   _setmode(STDOUT_FILENO, _O_BINARY);
    165 #endif
    166 
    167   CodeGeneratorRequest request;
    168   if (!request.ParseFromFileDescriptor(STDIN_FILENO)) {
    169     std::cerr << argv[0] << ": protoc sent unparseable request to plugin."
    170               << std::endl;
    171     return 1;
    172   }
    173 
    174   string error_msg;
    175   CodeGeneratorResponse response;
    176 
    177   if (GenerateCode(request, *generator, &response, &error_msg)) {
    178     if (!response.SerializeToFileDescriptor(STDOUT_FILENO)) {
    179       std::cerr << argv[0] << ": Error writing to stdout." << std::endl;
    180       return 1;
    181     }
    182   } else {
    183     if (!error_msg.empty()) {
    184       std::cerr << argv[0] << ": " << error_msg << std::endl;
    185     }
    186     return 1;
    187   }
    188 
    189   return 0;
    190 }
    191 
    192 }  // namespace compiler
    193 }  // namespace protobuf
    194 }  // namespace google
    195