|
|
|
@ -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, |
|
|
|
|