35 #include <google/protobuf/compiler/command_line_interface.h>
39 #include <google/protobuf/stubs/platform_macros.h>
42 #include <sys/types.h>
63 #if defined(__APPLE__)
64 #include <mach-o/dyld.h>
65 #elif defined(__FreeBSD__)
66 #include <sys/sysctl.h>
69 #include <google/protobuf/stubs/common.h>
70 #include <google/protobuf/stubs/logging.h>
71 #include <google/protobuf/stubs/stringprintf.h>
72 #include <google/protobuf/compiler/subprocess.h>
73 #include <google/protobuf/compiler/zip_writer.h>
74 #include <google/protobuf/compiler/plugin.pb.h>
75 #include <google/protobuf/compiler/code_generator.h>
76 #include <google/protobuf/compiler/importer.h>
77 #include <google/protobuf/io/coded_stream.h>
78 #include <google/protobuf/io/printer.h>
79 #include <google/protobuf/io/zero_copy_stream_impl.h>
80 #include <google/protobuf/descriptor.h>
81 #include <google/protobuf/dynamic_message.h>
82 #include <google/protobuf/text_format.h>
83 #include <google/protobuf/stubs/strutil.h>
84 #include <google/protobuf/stubs/substitute.h>
85 #include <google/protobuf/io/io_win32.h>
86 #include <google/protobuf/stubs/map_util.h>
87 #include <google/protobuf/stubs/stl_util.h>
90 #include <google/protobuf/port_def.inc>
98 #define O_BINARY _O_BINARY
100 #define O_BINARY 0 // If this isn't defined, the platform doesn't need it.
108 using google::protobuf::io::win32::access;
110 using google::protobuf::io::win32::mkdir;
112 using google::protobuf::io::win32::setmode;
116 static const char* kDefaultDirectDependenciesViolationMsg =
117 "File is imported but not declared in --direct_dependencies: %s";
123 #if defined(_WIN32) || defined(__CYGWIN__)
124 return text.size() >= 3 &&
text[1] ==
':' && isalpha(
text[0]) &&
125 (
text[2] ==
'/' ||
text[2] ==
'\\') &&
text.find_last_of(
':') == 1;
131 void SetFdToTextMode(
int fd) {
133 if (setmode(fd, _O_TEXT) == -1) {
141 void SetFdToBinaryMode(
int fd) {
143 if (setmode(fd, _O_BINARY) == -1) {
152 if (!
path->empty() &&
path->at(
path->size() - 1) !=
'/') {
153 path->push_back(
'/');
158 if (
path.empty())
return true;
161 std::cerr <<
path <<
": " << strerror(errno) << std::endl;
176 std::vector<std::string> parts =
179 for (
int i = 0;
i < parts.size() - 1;
i++) {
180 path_so_far += parts[
i];
181 if (mkdir(path_so_far.c_str(), 0777) != 0) {
182 if (errno != EEXIST) {
183 std::cerr <<
filename <<
": while trying to create directory "
184 << path_so_far <<
": " << strerror(errno) << std::endl;
198 int len = GetModuleFileNameA(NULL,
buffer, MAX_PATH);
199 #elif defined(__APPLE__)
203 char dirtybuffer[PATH_MAX];
205 if (_NSGetExecutablePath(dirtybuffer, &
size) == 0) {
206 realpath(dirtybuffer,
buffer);
209 #elif defined(__FreeBSD__)
211 size_t len = PATH_MAX;
212 int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
213 if (sysctl(mib, 4, &
buffer, &
len, NULL, 0) != 0) {
218 int len = readlink(
"/proc/self/exe",
buffer, PATH_MAX);
238 void AddDefaultProtoPaths(
239 std::vector<std::pair<std::string, std::string>>* paths) {
244 if (!GetProtocAbsolutePath(&
path)) {
248 size_t pos =
path.find_last_of(
"/\\");
249 if (
pos == std::string::npos ||
pos == 0) {
254 if (IsInstalledProtoPath(
path)) {
255 paths->push_back(std::pair<std::string, std::string>(
"",
path));
259 if (IsInstalledProtoPath(
path +
"/include")) {
261 std::pair<std::string, std::string>(
"",
path +
"/include"));
265 pos =
path.find_last_of(
"/\\");
266 if (
pos == std::string::npos ||
pos == 0) {
270 if (IsInstalledProtoPath(
path +
"/include")) {
272 std::pair<std::string, std::string>(
"",
path +
"/include"));
281 return plugin_prefix +
"gen-" + directive.substr(2, directive.size() - 6);
287 class CommandLineInterface::ErrorPrinter
289 public io::ErrorCollector,
290 public DescriptorPool::ErrorCollector {
357 out <<
":" << (
line + 1) <<
":" << (column + 1);
361 <<
" in column=" << (column + 1);
366 if (
type ==
"warning") {
409 const google::protobuf::GeneratedCodeInfo& info)
override;
420 std::map<std::string, std::string>
files_;
436 const google::protobuf::GeneratedCodeInfo& info);
455 size_t insertion_offset,
size_t insertion_length,
456 size_t indent_length);
462 size_t insertion_offset,
size_t indent_length,
463 google::protobuf::GeneratedCodeInfo& target_info);
477 std::unique_ptr<io::StringOutputStream>
inner_;
486 const std::vector<const FileDescriptor*>& parsed_files)
487 : parsed_files_(parsed_files), had_error_(
false) {}
495 if (!VerifyDirectoryExists(
prefix)) {
501 const char*
data =
pair.second.data();
514 }
while (file_descriptor < 0 && errno == EINTR);
516 if (file_descriptor < 0) {
527 }
while (write_result < 0 && errno == EINTR);
529 if (write_result <= 0) {
540 if (write_result < 0) {
544 std::cerr <<
filename <<
": write() returned zero?" << std::endl;
549 data += write_result;
550 size -= write_result;
553 if (
close(file_descriptor) != 0) {
574 }
while (file_descriptor < 0 && errno == EINTR);
576 if (file_descriptor < 0) {
583 io::FileOutputStream
stream(file_descriptor);
584 ZipWriter zip_writer(&
stream);
587 zip_writer.Write(
pair.first,
pair.second);
590 zip_writer.WriteDirectory();
592 if (
stream.GetErrno() != 0) {
593 std::cerr <<
filename <<
": " << strerror(
stream.GetErrno()) << std::endl;
598 std::cerr <<
filename <<
": " << strerror(
stream.GetErrno()) << std::endl;
606 auto pair =
files_.insert({
"META-INF/MANIFEST.MF",
""});
609 "Manifest-Version: 1.0\n"
610 "Created-By: 1.6.0 (protoc)\n"
616 std::vector<std::string>* output_filenames) {
618 output_filenames->push_back(
pair.first);
624 return new MemoryOutputStream(
this,
filename,
false);
630 return new MemoryOutputStream(
this,
filename,
true);
636 return new MemoryOutputStream(
this,
filename, insertion_point);
642 const google::protobuf::GeneratedCodeInfo& info) {
653 append_mode_(append_mode),
661 insertion_point_(insertion_point),
666 const std::string& insertion_point,
const google::protobuf::GeneratedCodeInfo& info)
669 insertion_point_(insertion_point),
671 info_to_insert_(info) {}
674 const std::string& insertion_content,
size_t insertion_offset,
675 size_t indent_length, google::protobuf::GeneratedCodeInfo& target_info) {
683 insertion_offset += indent_length;
684 for (
const auto& source_annotation : info_to_insert_.annotation()) {
686 int inner_indent = 0;
689 for (;
pos < source_annotation.end() &&
pos < insertion_content.size() - 1;
691 if (insertion_content[
pos] ==
'\n') {
692 if (
pos >= source_annotation.begin()) {
695 inner_indent += indent_length;
697 insertion_offset += indent_length;
701 *annotation = source_annotation;
703 insertion_offset += inner_indent;
704 annotation->
set_end(annotation->
end() + insertion_offset);
709 const std::string& insertion_content,
size_t insertion_offset,
710 size_t insertion_length,
size_t indent_length) {
711 auto it = directory_->files_.find(filename_ +
".pb.meta");
712 if (
it == directory_->files_.end() && info_to_insert_.annotation().empty()) {
717 bool is_text_format =
false;
719 if (
it != directory_->files_.end()) {
720 encoded_data = &
it->second;
724 if (!
metadata.ParseFromString(*encoded_data)) {
729 <<
".pb.meta: Could not parse metadata as wire or text format."
736 is_text_format =
true;
741 &directory_->files_.insert({filename_ +
".pb.meta",
""}).
first->second;
744 bool crossed_offset =
false;
746 for (
const auto& source_annotation :
metadata.annotation()) {
751 if (source_annotation.begin() >= insertion_offset && !crossed_offset) {
752 crossed_offset =
true;
753 InsertShiftedInfo(insertion_content, insertion_offset, indent_length,
755 to_add += insertion_length;
758 *annotation = source_annotation;
760 annotation->
set_end(annotation->
end() + to_add);
764 if (!crossed_offset) {
765 InsertShiftedInfo(insertion_content, insertion_offset, indent_length,
768 if (is_text_format) {
771 new_metadata.SerializeToString(encoded_data);
780 auto pair = directory_->files_.insert({filename_,
""});
782 bool already_present = !
pair.second;
784 if (insertion_point_.empty()) {
786 if (already_present) {
790 std::cerr << filename_ <<
": Tried to write the same file twice."
792 directory_->had_error_ =
true;
803 data_.push_back(
'\n');
807 if (!already_present) {
808 std::cerr << filename_
809 <<
": Tried to insert into file that doesn't exist."
811 directory_->had_error_ =
true;
819 std::string::size_type
pos =
target->find(magic_string);
821 if (
pos == std::string::npos) {
822 std::cerr << filename_ <<
": insertion point \"" << insertion_point_
823 <<
"\" not found." << std::endl;
824 directory_->had_error_ =
true;
828 if ((
pos > 3) && (
target->substr(
pos - 3, 2) ==
"/*")) {
838 if (
pos == std::string::npos) {
858 for (
int i = 0;
i <
data_.size();
i++) {
866 std::string::size_type data_pos = 0;
868 while (data_pos <
data_.size()) {
876 std::string::size_type line_length =
877 data_.find_first_of(
'\n', data_pos) + 1 - data_pos;
878 memcpy(target_ptr,
data_.data() + data_pos, line_length);
879 target_ptr += line_length;
880 data_pos += line_length;
892 #if defined(_WIN32) && !defined(__CYGWIN__)
900 kDefaultDirectDependenciesViolationMsg) {}
908 info.flag_name = flag_name;
909 info.generator = generator;
910 info.help_text = help_text;
918 info.flag_name = flag_name;
919 info.option_flag_name = option_flag_name;
920 info.generator = generator;
921 info.help_text = help_text;
933 for (
int i = 0;
i <
desc->field_count();
i++) {
934 if (
desc->field(i)->has_optional_keyword()) {
938 for (
int i = 0;
i <
desc->nested_type_count();
i++) {
939 if (ContainsProto3Optional(
desc->nested_type(i))) {
948 for (
int i = 0;
i <
file->message_type_count();
i++) {
949 if (ContainsProto3Optional(
file->message_type(i))) {
960 std::unique_ptr<SimpleDescriptorDatabase>
961 PopulateSingleSimpleDescriptorDatabase(
const std::string& descriptor_set_name);
975 std::vector<const FileDescriptor*> parsed_files;
976 std::unique_ptr<DiskSourceTree> disk_source_tree;
977 std::unique_ptr<ErrorPrinter> error_collector;
978 std::unique_ptr<DescriptorPool> descriptor_pool;
983 std::vector<std::unique_ptr<SimpleDescriptorDatabase>>
984 databases_per_descriptor_set;
985 std::unique_ptr<MergedDescriptorDatabase> descriptor_set_in_database;
987 std::unique_ptr<SourceTreeDescriptorDatabase> source_tree_database;
993 std::unique_ptr<SimpleDescriptorDatabase> database_for_descriptor_set =
994 PopulateSingleSimpleDescriptorDatabase(
name);
995 if (!database_for_descriptor_set) {
998 databases_per_descriptor_set.push_back(
1002 std::vector<DescriptorDatabase*> raw_databases_per_descriptor_set;
1003 raw_databases_per_descriptor_set.reserve(
1004 databases_per_descriptor_set.size());
1005 for (
const std::unique_ptr<SimpleDescriptorDatabase>& db :
1006 databases_per_descriptor_set) {
1007 raw_databases_per_descriptor_set.push_back(db.get());
1009 descriptor_set_in_database.reset(
1022 descriptor_pool.reset(
new DescriptorPool(descriptor_set_in_database.get(),
1023 error_collector.get()));
1027 descriptor_set_in_database.get())) {
1031 error_collector.reset(
1034 source_tree_database.reset(
new SourceTreeDescriptorDatabase(
1035 disk_source_tree.get(), descriptor_set_in_database.get()));
1036 source_tree_database->RecordErrorsTo(error_collector.get());
1039 source_tree_database.get(),
1040 source_tree_database->GetValidationErrorCollector()));
1043 descriptor_pool->EnforceWeakDependencies(
true);
1062 AddTrailingSlash(&output_location);
1065 auto& generator = output_directories[output_location];
1069 generator.reset(
new GeneratorContextImpl(parsed_files));
1080 for (
const auto&
pair : output_directories) {
1084 if (!
directory->WriteAllToDisk(location)) {
1092 if (!
directory->WriteAllToZip(location)) {
1101 disk_source_tree.get())) {
1117 file.set_name(
"empty_message.proto");
1118 file.add_message_type()->set_name(
"EmptyMessage");
1131 if (error_collector->FoundErrors() ||
1139 for (
int i = 0;
i < parsed_files.size(); ++
i) {
1141 for (
int j = 0;
j < fd->message_type_count(); ++
j) {
1147 GOOGLE_LOG(
ERROR) <<
"If the code reaches here, it usually means a bug of "
1148 "flag parsing in the CommandLineInterface.";
1176 std::unique_ptr<SimpleDescriptorDatabase>
1177 PopulateSingleSimpleDescriptorDatabase(
const std::string& descriptor_set_name) {
1180 fd =
open(descriptor_set_name.c_str(), O_RDONLY |
O_BINARY);
1181 }
while (fd < 0 && errno == EINTR);
1183 std::cerr << descriptor_set_name <<
": " << strerror(ENOENT) << std::endl;
1188 bool parsed = file_descriptor_set.ParseFromFileDescriptor(fd);
1189 if (
close(fd) != 0) {
1190 std::cerr << descriptor_set_name <<
": close: " << strerror(errno)
1196 std::cerr << descriptor_set_name <<
": Unable to parse." << std::endl;
1200 std::unique_ptr<SimpleDescriptorDatabase>
database{
1203 for (
int j = 0;
j < file_descriptor_set.
file_size();
j++) {
1205 if (
database->FindFileByName(file_descriptor_set.
file(j).name(),
1206 &previously_added_file_descriptor_proto)) {
1224 if (!
database->FindFileByName(input_file, &file_descriptor)) {
1225 std::cerr <<
"Could not find file in descriptor database: " << input_file
1226 <<
": " << strerror(ENOENT) << std::endl;
1232 std::cerr << file_descriptor.
name()
1233 <<
": This file contains services, but "
1234 "--disallow_services was used."
1245 std::vector<const FileDescriptor*>* parsed_files) {
1273 if (parsed_file == NULL) {
1277 parsed_files->push_back(parsed_file);
1281 std::cerr << parsed_file->
name()
1282 <<
": This file contains services, but "
1283 "--disallow_services was used."
1292 bool indirect_imports =
false;
1296 indirect_imports =
true;
1297 std::cerr << parsed_file->
name() <<
": "
1304 if (indirect_imports) {
1343 bool in_fallback_database =
1344 fallback_database !=
nullptr &&
1351 if (source_tree->VirtualFileToDiskFile(*proto, &disk_file) ||
1352 in_fallback_database) {
1355 std::cerr <<
"Could not make proto path relative: " << *proto <<
": "
1356 << strerror(ENOENT) << std::endl;
1362 switch (source_tree->DiskFileToVirtualFile(*proto, &virtual_file,
1363 &shadowing_disk_file)) {
1365 *proto = virtual_file;
1368 std::cerr << *proto <<
": Input is shadowed in the --proto_path by \""
1369 << shadowing_disk_file
1370 <<
"\". Either use the latter file as your input or reorder "
1371 "the --proto_path so that the former file's location "
1376 if (in_fallback_database) {
1379 std::string error_str = source_tree->GetLastErrorMessage().empty()
1381 : source_tree->GetLastErrorMessage();
1382 std::cerr <<
"Could not map to virtual file: " << *proto <<
": "
1383 << error_str << std::endl;
1389 if (source_tree->VirtualFileToDiskFile(*proto, &disk_file) ||
1390 in_fallback_database) {
1397 <<
": File does not reside within any path "
1398 "specified using --proto_path (or -I). You must specify a "
1399 "--proto_path which encompasses this file. Note that the "
1400 "proto_path must be an exact prefix of the .proto file "
1401 "names -- protoc is too dumb to figure out when two paths "
1402 "(e.g. absolute and relative) are equivalent (it's harder "
1416 fallback_database)) {
1429 std::ifstream file_stream(
file.c_str());
1430 if (!file_stream.is_open()) {
1435 while (std::getline(file_stream,
argument)) {
1442 int argc,
const char*
const argv[]) {
1445 std::vector<std::string> arguments;
1446 for (
int i = 1;
i < argc; ++
i) {
1447 if (argv[i][0] ==
'@') {
1449 std::cerr <<
"Failed to open argument file: " << (argv[
i] + 1)
1455 arguments.push_back(argv[i]);
1459 if (arguments.empty()) {
1465 for (
int i = 0;
i < arguments.size(); ++
i) {
1470 if (i + 1 == arguments.size() || arguments[i + 1][0] ==
'-') {
1471 std::cerr <<
"Missing value for flag: " <<
name << std::endl;
1472 if (
name ==
"--decode") {
1473 std::cerr <<
"To decode an unknown message, use --decode_raw."
1488 bool foundUnknownPluginOption =
false;
1489 for (std::map<std::string, std::string>::const_iterator i =
1495 bool foundImplicitPlugin =
false;
1496 for (std::vector<OutputDirective>::const_iterator j =
1499 if (
j->generator == NULL) {
1501 if (plugin_name ==
i->first) {
1502 foundImplicitPlugin =
true;
1507 if (!foundImplicitPlugin) {
1508 std::cerr <<
"Unknown flag: "
1512 foundUnknownPluginOption =
true;
1515 if (foundUnknownPluginOption) {
1525 proto_path_.push_back(std::pair<std::string, std::string>(
"",
"."));
1529 bool missing_proto_definitions =
false;
1540 <<
"When using --decode_raw, no input files should be given."
1544 missing_proto_definitions =
false;
1548 PROTOBUF_FALLTHROUGH_INTENDED;
1551 missing_proto_definitions =
1557 if (missing_proto_definitions) {
1558 std::cerr <<
"Missing input file." << std::endl;
1563 std::cerr <<
"Missing output directives." << std::endl;
1567 std::cerr <<
"Can only use --dependency_out=FILE when generating code."
1572 std::cerr <<
"Can only use --deterministic_output with --encode."
1578 <<
"Can only process one input file when using --dependency_out=FILE."
1583 std::cerr <<
"--include_imports only makes sense when combined with "
1584 "--descriptor_set_out."
1588 std::cerr <<
"--include_source_info only makes sense when combined with "
1589 "--descriptor_set_out."
1598 bool parsed_value =
false;
1600 if (
arg[0] !=
'-') {
1603 parsed_value =
true;
1605 }
else if (
arg[1] ==
'-') {
1608 const char* equals_pos = strchr(
arg,
'=');
1609 if (equals_pos != NULL) {
1611 *
value = equals_pos + 1;
1612 parsed_value =
true;
1619 if (
arg[1] ==
'\0') {
1624 parsed_value =
true;
1628 parsed_value = !
value->empty();
1640 if (*
name ==
"-h" || *
name ==
"--help" || *
name ==
"--disallow_services" ||
1641 *
name ==
"--include_imports" || *
name ==
"--include_source_info" ||
1642 *
name ==
"--version" || *
name ==
"--decode_raw" ||
1643 *
name ==
"--print_free_field_numbers" ||
1644 *
name ==
"--experimental_allow_proto3_optional" ||
1645 *
name ==
"--deterministic_output" || *
name ==
"--fatal_warnings") {
1661 if (
value.empty()) {
1663 <<
"You seem to have passed an empty string as one of the "
1666 <<
". This is actually "
1667 "sort of hard to do. Congrats. Unfortunately it is not valid "
1668 "input so the program is going to die now."
1676 switch (google::protobuf::io::win32::ExpandWildcards(
1678 [
this](
const string&
path) { this->input_files_.push_back(
path); })) {
1679 case google::protobuf::io::win32::ExpandWildcardsResult::kSuccess:
1681 case google::protobuf::io::win32::ExpandWildcardsResult::
1682 kErrorNoMatchingFile:
1685 std::cerr <<
"Invalid file name pattern or missing input file \""
1686 <<
value <<
"\"" << std::endl;
1689 std::cerr <<
"Cannot convert path \"" <<
value
1690 <<
"\" to or from Windows style" << std::endl;
1699 }
else if (
name ==
"-I" ||
name ==
"--proto_path") {
1703 std::vector<std::string> parts =
Split(
1707 for (
int i = 0;
i < parts.size();
i++) {
1711 std::string::size_type equals_pos = parts[
i].find_first_of(
'=');
1712 if (equals_pos == std::string::npos) {
1714 disk_path = parts[
i];
1716 virtual_path = parts[
i].substr(0, equals_pos);
1717 disk_path = parts[
i].substr(equals_pos + 1);
1720 if (disk_path.empty()) {
1722 <<
"--proto_path passed empty directory name. (Use \".\" for "
1723 "current directory.)"
1732 std::cerr << disk_path <<
": warning: directory does not exist."
1736 disk_path = parts[
i];
1744 std::pair<std::string, std::string>(virtual_path, disk_path));
1747 }
else if (
name ==
"--direct_dependencies") {
1750 <<
" may only be passed once. To specify multiple "
1751 "direct dependencies, pass them all as a single "
1752 "parameter separated by ':'."
1758 std::vector<std::string> direct =
1763 }
else if (
name ==
"--direct_dependencies_violation_msg") {
1766 }
else if (
name ==
"--descriptor_set_in") {
1769 <<
" may only be passed once. To specify multiple "
1770 "descriptor sets, pass them all as a single "
1771 "parameter separated by '"
1775 if (
value.empty()) {
1776 std::cerr <<
name <<
" requires a non-empty value." << std::endl;
1780 std::cerr <<
name <<
" cannot be used with --dependency_out."
1789 }
else if (
name ==
"-o" ||
name ==
"--descriptor_set_out") {
1791 std::cerr <<
name <<
" may only be passed once." << std::endl;
1794 if (
value.empty()) {
1795 std::cerr <<
name <<
" requires a non-empty value." << std::endl;
1800 <<
"Cannot use --encode or --decode and generate descriptors at the "
1807 }
else if (
name ==
"--dependency_out") {
1809 std::cerr <<
name <<
" may only be passed once." << std::endl;
1812 if (
value.empty()) {
1813 std::cerr <<
name <<
" requires a non-empty value." << std::endl;
1817 std::cerr <<
name <<
" cannot be used with --descriptor_set_in."
1823 }
else if (
name ==
"--include_imports") {
1825 std::cerr <<
name <<
" may only be passed once." << std::endl;
1830 }
else if (
name ==
"--include_source_info") {
1832 std::cerr <<
name <<
" may only be passed once." << std::endl;
1837 }
else if (
name ==
"-h" ||
name ==
"--help") {
1841 }
else if (
name ==
"--version") {
1846 << PROTOBUF_VERSION_SUFFIX << std::endl;
1849 }
else if (
name ==
"--disallow_services") {
1853 }
else if (
name ==
"--experimental_allow_proto3_optional") {
1855 }
else if (
name ==
"--encode" ||
name ==
"--decode" ||
1856 name ==
"--decode_raw") {
1858 std::cerr <<
"Only one of --encode and --decode can be specified."
1863 std::cerr <<
"Cannot use " <<
name
1864 <<
" and generate code or descriptors at the same time."
1871 if (
value.empty() &&
name !=
"--decode_raw") {
1872 std::cerr <<
"Type name for " <<
name <<
" cannot be blank." << std::endl;
1873 if (
name ==
"--decode") {
1874 std::cerr <<
"To decode an unknown message, use --decode_raw."
1878 }
else if (!
value.empty() &&
name ==
"--decode_raw") {
1879 std::cerr <<
"--decode_raw does not take a parameter." << std::endl;
1885 }
else if (
name ==
"--deterministic_output") {
1888 }
else if (
name ==
"--error_format") {
1889 if (
value ==
"gcc") {
1891 }
else if (
value ==
"msvs") {
1894 std::cerr <<
"Unknown error format: " <<
value << std::endl;
1898 }
else if (
name ==
"--fatal_warnings") {
1900 std::cerr <<
name <<
" may only be passed once." << std::endl;
1904 }
else if (
name ==
"--plugin") {
1906 std::cerr <<
"This compiler does not support plugins." << std::endl;
1913 std::string::size_type equals_pos =
value.find_first_of(
'=');
1914 if (equals_pos == std::string::npos) {
1916 std::string::size_type slash_pos =
value.find_last_of(
'/');
1917 if (slash_pos == std::string::npos) {
1918 plugin_name =
value;
1920 plugin_name =
value.substr(slash_pos + 1);
1924 plugin_name =
value.substr(0, equals_pos);
1930 }
else if (
name ==
"--print_free_field_numbers") {
1932 std::cerr <<
"Cannot use " <<
name
1933 <<
" and use --encode, --decode or print "
1934 <<
"other info at the same time." << std::endl;
1938 std::cerr <<
"Cannot use " <<
name
1939 <<
" and generate code or descriptors at the same time."
1947 const GeneratorInfo* generator_info =
1949 if (generator_info == NULL &&
1953 if (generator_info != NULL) {
1968 std::cerr <<
"Unknown flag: " <<
name << std::endl;
1974 std::cerr <<
"Cannot use --encode, --decode or print .proto info and "
1975 "generate code at the same time."
1980 OutputDirective directive;
1981 directive.name =
name;
1982 if (generator_info == NULL) {
1983 directive.generator = NULL;
1985 directive.generator = generator_info->generator;
1991 std::string::size_type colon_pos =
value.find_first_of(
':');
1993 directive.output_location =
value;
1995 directive.parameter =
value.substr(0, colon_pos);
1996 directive.output_location =
value.substr(colon_pos + 1);
2010 Parse PROTO_FILES and generate output based on the options given:
2011 -IPATH, --proto_path=PATH Specify the directory in which to search for
2012 imports. May be specified multiple times;
2013 directories will be searched in order. If not
2014 given, the current working directory is used.
2015 If not found in any of the these directories,
2016 the --descriptor_set_in descriptors will be
2017 checked for required proto file.
2018 --version Show version info and exit.
2019 -h, --help Show this text and exit.
2020 --encode=MESSAGE_TYPE Read a text-format message of the given type
2021 from standard input and write it in binary
2022 to standard output. The message type must
2023 be defined in PROTO_FILES or their imports.
2024 --deterministic_output When using --encode, ensure map fields are
2025 deterministically ordered. Note that this order
2026 is not canonical, and changes across builds or
2028 --decode=MESSAGE_TYPE Read a binary message of the given type from
2029 standard input and write it in text format
2030 to standard output. The message type must
2031 be defined in PROTO_FILES or their imports.
2032 --decode_raw Read an arbitrary protocol message from
2033 standard input and write the raw tag/value
2034 pairs in text format to standard output. No
2035 PROTO_FILES should be given when using this
2037 --descriptor_set_in=FILES Specifies a delimited list of FILES
2038 each containing a FileDescriptorSet (a
2039 protocol buffer defined in descriptor.proto).
2040 The FileDescriptor for each of the PROTO_FILES
2041 provided will be loaded from these
2042 FileDescriptorSets. If a FileDescriptor
2043 appears multiple times, the first occurrence
2045 -oFILE, Writes a FileDescriptorSet (a protocol buffer,
2046 --descriptor_set_out=FILE defined in descriptor.proto) containing all of
2047 the input files to FILE.
2048 --include_imports When using --descriptor_set_out, also include
2049 all dependencies of the input files in the
2050 set, so that the set is self-contained.
2051 --include_source_info When using --descriptor_set_out, do not strip
2052 SourceCodeInfo from the FileDescriptorProto.
2053 This results in vastly larger descriptors that
2054 include information about the original
2055 location of each decl in the source file as
2056 well as surrounding comments.
2057 --dependency_out=FILE Write a dependency output file in the format
2058 expected by make. This writes the transitive
2059 set of input file paths to FILE
2060 --error_format=FORMAT Set the format in which to print errors.
2061 FORMAT may be 'gcc' (the default) or 'msvs'
2062 (Microsoft Visual Studio format).
2063 --fatal_warnings Make warnings be fatal (similar to -Werr in
2064 gcc). This flag will make protoc return
2065 with a non-zero exit code if any warnings
2067 --print_free_field_numbers Print the free field numbers of the messages
2068 defined in the given proto files. Groups share
2069 the same field number space with the parent
2070 message. Extension ranges are counted as
2071 occupied fields numbers.)";
2074 --plugin=EXECUTABLE Specifies a plugin executable to use.
2075 Normally, protoc searches the PATH for
2076 plugins, but you may specify additional
2077 executables not in the path using this flag.
2078 Additionally, EXECUTABLE may be of the form
2079 NAME=PATH, in which case the given plugin name
2080 is mapped to the given executable even if
2081 the executable's own name differs.)";
2089 std::cout << std::endl
2090 <<
" " <<
iter->first <<
"=OUT_DIR "
2093 <<
iter->second.help_text;
2096 @<filename> Read options and filenames from file. If a
2097 relative file path is specified, the file
2098 will be searched in the working directory.
2099 The --proto_path option will not affect how
2100 this argument file is searched. Content of
2101 the file will be expanded in the position of
2102 @<filename> as in the argument list. Note
2103 that shell expansion is not applied to the
2104 content of the file (i.e., you cannot use
2105 quotes, wildcards, escapes, commands, etc.).
2106 Each line corresponds to a single argument,
2107 even if it contains spaces.)";
2108 std::cout << std::endl;
2113 const std::vector<const FileDescriptor*>& parsed_files)
const {
2114 bool supports_proto3_optional =
2116 if (!supports_proto3_optional) {
2117 for (
const auto fd : parsed_files) {
2118 if (ContainsProto3Optional(fd)) {
2119 std::cerr << fd->name()
2120 <<
": is a proto3 file that contains optional fields, but "
2123 <<
" hasn't been updated to support optional fields in "
2124 "proto3. Please ask the owner of this code generator to "
2125 "support proto3 optional.";
2134 const std::vector<const FileDescriptor*>& parsed_files,
2135 const OutputDirective& output_directive,
2139 if (output_directive.generator == NULL) {
2143 <<
"Bad name for plugin generator: " << output_directive.name;
2154 generator_context, &
error)) {
2155 std::cerr << output_directive.name <<
": " <<
error << std::endl;
2168 output_directive.name,
2169 output_directive.generator->GetSupportedFeatures(), parsed_files)) {
2173 if (!output_directive.generator->GenerateAll(parsed_files,
parameters,
2174 generator_context, &
error)) {
2176 std::cerr << output_directive.name <<
": " <<
error << std::endl;
2185 const std::vector<const FileDescriptor*>& parsed_files,
2190 std::set<const FileDescriptor*> already_seen;
2191 for (
int i = 0;
i < parsed_files.size();
i++) {
2196 std::vector<std::string> output_filenames;
2197 for (
const auto&
pair : output_directories) {
2200 std::vector<std::string> relative_output_filenames;
2201 directory->GetOutputFilenames(&relative_output_filenames);
2202 for (
int i = 0;
i < relative_output_filenames.size();
i++) {
2203 std::string output_filename = location + relative_output_filenames[
i];
2204 if (output_filename.compare(0, 2,
"./") == 0) {
2205 output_filename = output_filename.substr(2);
2207 output_filenames.push_back(output_filename);
2214 O_WRONLY | O_CREAT | O_TRUNC |
O_BINARY, 0666);
2215 }
while (fd < 0 && errno == EINTR);
2222 io::FileOutputStream
out(fd);
2225 for (
int i = 0;
i < output_filenames.size();
i++) {
2226 printer.Print(output_filenames[i].
c_str());
2227 if (i == output_filenames.size() - 1) {
2230 printer.Print(
" \\\n");
2239 source_tree->VirtualFileToDiskFile(virtual_file, &disk_file)) {
2240 printer.Print(
" $disk_file$",
"disk_file", disk_file);
2241 if (i < file_set.
file_size() - 1) printer.Print(
"\\\n");
2243 std::cerr <<
"Unable to identify path for file " << virtual_file
2253 const std::vector<const FileDescriptor*>& parsed_files,
2262 if (!processed_parameter.empty()) {
2263 request.set_parameter(processed_parameter);
2267 std::set<const FileDescriptor*> already_seen;
2268 for (
int i = 0;
i < parsed_files.size();
i++) {
2269 request.add_file_to_generate(parsed_files[i]->
name());
2273 &already_seen,
request.mutable_proto_file());
2277 request.mutable_compiler_version();
2281 version->set_suffix(PROTOBUF_VERSION_SUFFIX);
2286 if (
plugins_.count(plugin_name) > 0) {
2293 if (!subprocess.Communicate(
request, &
response, &communicate_error)) {
2300 std::unique_ptr<io::ZeroCopyOutputStream> current_output;
2301 for (
int i = 0;
i <
response.file_size();
i++) {
2302 const CodeGeneratorResponse::File& output_file =
response.file(i);
2304 if (!output_file.insertion_point().empty()) {
2309 current_output.reset();
2310 current_output.reset(
2311 generator_context->OpenForInsertWithGeneratedCodeInfo(
2312 filename, output_file.insertion_point(),
2313 output_file.generated_code_info()));
2314 }
else if (!output_file.name().empty()) {
2318 current_output.reset();
2319 current_output.reset(generator_context->Open(output_file.name()));
2320 }
else if (current_output == NULL) {
2322 "$0: First file chunk returned by plugin did not specify a file "
2331 writer.WriteString(output_file.content());
2340 plugin_name,
response.supported_features(), parsed_files)) {
2351 std::cerr <<
"Type not defined: " <<
codec_type_ << std::endl;
2356 std::unique_ptr<Message>
message(dynamic_factory.GetPrototype(
type)->New());
2359 SetFdToTextMode(STDIN_FILENO);
2360 SetFdToBinaryMode(STDOUT_FILENO);
2362 SetFdToBinaryMode(STDIN_FILENO);
2363 SetFdToTextMode(STDOUT_FILENO);
2366 io::FileInputStream
in(STDIN_FILENO);
2367 io::FileOutputStream
out(STDOUT_FILENO);
2372 TextFormat::Parser
parser;
2373 parser.RecordErrorsTo(&error_collector);
2374 parser.AllowPartialMessage(
true);
2377 std::cerr <<
"Failed to parse input." << std::endl;
2382 if (!
message->ParsePartialFromZeroCopyStream(&
in)) {
2383 std::cerr <<
"Failed to parse input." << std::endl;
2388 if (!
message->IsInitialized()) {
2389 std::cerr <<
"warning: Input message is missing required fields: "
2390 <<
message->InitializationErrorString() << std::endl;
2397 if (!
message->SerializePartialToCodedStream(&coded_out)) {
2398 std::cerr <<
"output: I/O error." << std::endl;
2404 std::cerr <<
"output: I/O error." << std::endl;
2413 const std::vector<const FileDescriptor*>& parsed_files) {
2416 std::set<const FileDescriptor*> already_seen;
2422 std::set<const FileDescriptor*> to_output;
2423 to_output.insert(parsed_files.begin(), parsed_files.end());
2424 for (
int i = 0;
i < parsed_files.size();
i++) {
2426 for (
int j = 0;
j <
file->dependency_count();
j++) {
2429 if (to_output.find(dependency) == to_output.end()) {
2430 already_seen.insert(dependency);
2435 for (
int i = 0;
i < parsed_files.size();
i++) {
2445 O_WRONLY | O_CREAT | O_TRUNC |
O_BINARY, 0666);
2446 }
while (fd < 0 && errno == EINTR);
2453 io::FileOutputStream
out(fd);
2459 coded_out.SetSerializationDeterministic(
true);
2460 if (!file_set.SerializeToCodedStream(&coded_out)) {
2479 bool include_source_code_info,
2480 std::set<const FileDescriptor*>* already_seen,
2481 RepeatedPtrField<FileDescriptorProto>*
output) {
2482 if (!already_seen->insert(
file).second) {
2488 for (
int i = 0;
i <
file->dependency_count();
i++) {
2490 include_source_code_info, already_seen,
output);
2495 file->CopyTo(new_descriptor);
2496 if (include_json_name) {
2497 file->CopyJsonNameTo(new_descriptor);
2499 if (include_source_code_info) {
2500 file->CopySourceCodeInfoTo(new_descriptor);
2538 void GatherOccupiedFieldRanges(
2540 std::vector<const Descriptor*>* nested_messages) {
2541 std::set<const Descriptor*>
groups;
2544 ranges->insert(
FieldRange(fd->number(), fd->number() + 1));
2546 groups.insert(fd->message_type());
2549 for (
int i = 0;
i <
descriptor->extension_range_count(); ++
i) {
2553 for (
int i = 0;
i <
descriptor->reserved_range_count(); ++
i) {
2559 for (
int i = 0;
i <
descriptor->nested_type_count(); ++
i) {
2562 GatherOccupiedFieldRanges(nested_desc, ranges, nested_messages);
2564 nested_messages->push_back(nested_desc);
2573 const std::set<FieldRange>& ranges) {
2576 int next_free_number = 1;
2577 for (std::set<FieldRange>::const_iterator i = ranges.begin();
2578 i != ranges.end(); ++i) {
2581 if (next_free_number >=
i->second)
continue;
2583 if (next_free_number < i->
first) {
2584 if (next_free_number + 1 ==
i->first) {
2592 next_free_number =
i->second;
2597 std::cout <<
output << std::endl;
2603 std::set<FieldRange> ranges;
2604 std::vector<const Descriptor*> nested_messages;
2605 GatherOccupiedFieldRanges(
descriptor, &ranges, &nested_messages);
2607 for (
int i = 0;
i < nested_messages.size(); ++
i) {
2610 FormatFreeFieldNumbers(
descriptor->full_name(), ranges);