1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <google/protobuf/compiler/importer.h> 18 #include <google/protobuf/dynamic_message.h> 19 #include <google/protobuf/io/printer.h> 20 #include <google/protobuf/io/zero_copy_stream_impl.h> 21 #include <google/protobuf/stubs/strutil.h> 22 #include <google/protobuf/util/field_comparator.h> 23 #include <google/protobuf/util/message_differencer.h> 24 25 #include <stdio.h> 26 27 #include <fstream> 28 #include <iostream> 29 30 #include "perfetto/base/logging.h" 31 32 using namespace google::protobuf; 33 using namespace google::protobuf::compiler; 34 using namespace google::protobuf::io; 35 36 namespace { 37 38 static const char kHeader[] = R"(/* 39 * Copyright (C) 2017 The Android Open Source Project 40 * 41 * Licensed under the Apache License, Version 2.0 (the "License"); 42 * you may not use this file except in compliance with the License. 43 * You may obtain a copy of the License at 44 * 45 * http://www.apache.org/licenses/LICENSE-2.0 46 * 47 * Unless required by applicable law or agreed to in writing, software 48 * distributed under the License is distributed on an "AS IS" BASIS, 49 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 50 * See the License for the specific language governing permissions and 51 * limitations under the License. 52 */ 53 54 /******************************************************************************* 55 * AUTOGENERATED - DO NOT EDIT 56 ******************************************************************************* 57 * This file has been generated from the protobuf message 58 * $p$ 59 * by 60 * $f$. 61 * If you need to make changes here, change the .proto file and then run 62 * ./tools/gen_tracing_cpp_headers_from_protos 63 */ 64 65 )"; 66 67 class ErrorPrinter : public MultiFileErrorCollector { 68 virtual void AddError(const string& filename, 69 int line, 70 int col, 71 const string& msg) { 72 PERFETTO_ELOG("%s %d:%d: %s", filename.c_str(), line, col, msg.c_str()); 73 } 74 virtual void AddWarning(const string& filename, 75 int line, 76 int col, 77 const string& msg) { 78 PERFETTO_ILOG("%s %d:%d: %s", filename.c_str(), line, col, msg.c_str()); 79 } 80 }; 81 82 std::string GetProtoHeader(const FileDescriptor* proto_file) { 83 return StringReplace(proto_file->name(), ".proto", ".pb.h", false); 84 } 85 86 std::string GetFwdDeclType(const Descriptor* msg, bool with_namespace = false) { 87 std::string full_type; 88 full_type.append(msg->name()); 89 for (const Descriptor* par = msg->containing_type(); par; 90 par = par->containing_type()) { 91 full_type.insert(0, par->name() + "_"); 92 } 93 if (with_namespace) { 94 std::vector<std::string> namespaces = Split(msg->file()->package(), "."); 95 for (auto it = namespaces.rbegin(); it != namespaces.rend(); it++) { 96 full_type.insert(0, *it + "::"); 97 } 98 } 99 return full_type; 100 } 101 102 void GenFwdDecl(const Descriptor* msg, Printer* p) { 103 p->Print("class $n$;", "n", GetFwdDeclType(msg)); 104 105 // Recurse into subtypes 106 for (int i = 0; i < msg->field_count(); i++) { 107 const FieldDescriptor* field = msg->field(i); 108 if (field->type() == FieldDescriptor::TYPE_MESSAGE) 109 GenFwdDecl(field->message_type(), p); 110 } 111 } 112 113 } // namespace 114 115 class ProtoToCpp { 116 public: 117 ProtoToCpp(const std::string& header_dir, 118 const std::string& cpp_dir, 119 const std::string& include_path); 120 121 static std::string GetCppType(const FieldDescriptor* field, bool constref); 122 123 void Convert(const std::string& src_proto); 124 std::string GetHeaderPath(const FileDescriptor*); 125 std::string GetCppPath(const FileDescriptor*); 126 std::string GetIncludePath(const FileDescriptor*); 127 void GenHeader(const Descriptor*, Printer*); 128 void GenCpp(const Descriptor*, Printer*, std::string prefix); 129 130 private: 131 std::string header_dir_; 132 std::string cpp_dir_; 133 std::string include_path_; 134 DiskSourceTree dst_; 135 ErrorPrinter error_printer_; 136 Importer importer_; 137 }; 138 139 ProtoToCpp::ProtoToCpp(const std::string& header_dir, 140 const std::string& cpp_dir, 141 const std::string& include_path) 142 : header_dir_(header_dir), 143 cpp_dir_(cpp_dir), 144 include_path_(include_path), 145 importer_(&dst_, &error_printer_) { 146 dst_.MapPath("", "protos"); 147 } 148 149 std::string ProtoToCpp::GetHeaderPath(const FileDescriptor* proto_file) { 150 std::string basename = Split(proto_file->name(), "/").back(); 151 return header_dir_ + "/" + StringReplace(basename, ".proto", ".h", false); 152 } 153 154 std::string ProtoToCpp::GetCppPath(const FileDescriptor* proto_file) { 155 std::string basename = Split(proto_file->name(), "/").back(); 156 return cpp_dir_ + "/" + StringReplace(basename, ".proto", ".cc", false); 157 } 158 159 std::string ProtoToCpp::GetIncludePath(const FileDescriptor* proto_file) { 160 std::string basename = Split(proto_file->name(), "/").back(); 161 return include_path_ + "/" + StringReplace(basename, ".proto", ".h", false); 162 } 163 164 std::string ProtoToCpp::GetCppType(const FieldDescriptor* field, 165 bool constref) { 166 switch (field->type()) { 167 case FieldDescriptor::TYPE_DOUBLE: 168 return "double"; 169 case FieldDescriptor::TYPE_FLOAT: 170 return "float"; 171 case FieldDescriptor::TYPE_FIXED32: 172 case FieldDescriptor::TYPE_UINT32: 173 return "uint32_t"; 174 case FieldDescriptor::TYPE_SFIXED32: 175 case FieldDescriptor::TYPE_INT32: 176 case FieldDescriptor::TYPE_SINT32: 177 return "int32_t"; 178 case FieldDescriptor::TYPE_FIXED64: 179 case FieldDescriptor::TYPE_UINT64: 180 return "uint64_t"; 181 case FieldDescriptor::TYPE_SFIXED64: 182 case FieldDescriptor::TYPE_SINT64: 183 case FieldDescriptor::TYPE_INT64: 184 return "int64_t"; 185 case FieldDescriptor::TYPE_BOOL: 186 return "bool"; 187 case FieldDescriptor::TYPE_STRING: 188 case FieldDescriptor::TYPE_BYTES: 189 return constref ? "const std::string&" : "std::string"; 190 case FieldDescriptor::TYPE_MESSAGE: 191 return constref ? "const " + field->message_type()->name() + "&" 192 : field->message_type()->name(); 193 case FieldDescriptor::TYPE_ENUM: 194 return field->enum_type()->name(); 195 case FieldDescriptor::TYPE_GROUP: 196 PERFETTO_FATAL("No cpp type for a group field."); 197 } 198 PERFETTO_FATAL("Not reached"); // for gcc 199 } 200 201 void ProtoToCpp::Convert(const std::string& src_proto) { 202 const FileDescriptor* proto_file = importer_.Import(src_proto); 203 if (!proto_file) { 204 PERFETTO_ELOG("Failed to load %s", src_proto.c_str()); 205 exit(1); 206 } 207 208 std::string dst_header = GetHeaderPath(proto_file); 209 std::string dst_cpp = GetCppPath(proto_file); 210 211 std::ofstream header_ostr; 212 header_ostr.open(dst_header); 213 PERFETTO_CHECK(header_ostr.is_open()); 214 OstreamOutputStream header_proto_ostr(&header_ostr); 215 Printer header_printer(&header_proto_ostr, '$'); 216 217 std::ofstream cpp_ostr; 218 cpp_ostr.open(dst_cpp); 219 PERFETTO_CHECK(cpp_ostr.is_open()); 220 OstreamOutputStream cpp_proto_ostr(&cpp_ostr); 221 Printer cpp_printer(&cpp_proto_ostr, '$'); 222 223 std::string include_guard = dst_header + "_"; 224 UpperString(&include_guard); 225 StripString(&include_guard, ".-/\\", '_'); 226 header_printer.Print(kHeader, "f", __FILE__, "p", src_proto); 227 header_printer.Print("#ifndef $g$\n#define $g$\n\n", "g", include_guard); 228 header_printer.Print("#include <stdint.h>\n"); 229 header_printer.Print("#include <vector>\n"); 230 header_printer.Print("#include <string>\n"); 231 header_printer.Print("#include <type_traits>\n\n"); 232 header_printer.Print("#include \"perfetto/base/export.h\"\n\n"); 233 234 cpp_printer.Print(kHeader, "f", __FILE__, "p", src_proto); 235 PERFETTO_CHECK(dst_header.find("include/") == 0); 236 cpp_printer.Print("#include \"$f$\"\n", "f", 237 dst_header.substr(strlen("include/"))); 238 239 // Generate includes for translated types of dependencies. 240 for (int i = 0; i < proto_file->dependency_count(); i++) { 241 const FileDescriptor* dep = proto_file->dependency(i); 242 header_printer.Print("#include \"$f$\"\n", "f", GetIncludePath(dep)); 243 } 244 header_printer.Print("\n"); 245 246 cpp_printer.Print("\n#include \"$f$\"\n", "f", GetProtoHeader(proto_file)); 247 for (int i = 0; i < proto_file->dependency_count(); i++) { 248 const FileDescriptor* dep = proto_file->dependency(i); 249 cpp_printer.Print("#include \"$f$\"\n", "f", GetProtoHeader(dep)); 250 } 251 252 // Generate forward declarations in the header for proto types. 253 header_printer.Print("// Forward declarations for protobuf types.\n"); 254 std::vector<std::string> namespaces = Split(proto_file->package(), "."); 255 for (size_t i = 0; i < namespaces.size(); i++) 256 header_printer.Print("namespace $n$ {\n", "n", namespaces[i]); 257 for (int i = 0; i < proto_file->message_type_count(); i++) 258 GenFwdDecl(proto_file->message_type(i), &header_printer); 259 for (size_t i = 0; i < namespaces.size(); i++) 260 header_printer.Print("}\n"); 261 262 header_printer.Print("\nnamespace perfetto {\n"); 263 cpp_printer.Print("\nnamespace perfetto {\n"); 264 265 for (int i = 0; i < proto_file->message_type_count(); i++) { 266 const Descriptor* msg = proto_file->message_type(i); 267 GenHeader(msg, &header_printer); 268 GenCpp(msg, &cpp_printer, ""); 269 } 270 271 cpp_printer.Print("} // namespace perfetto\n"); 272 header_printer.Print("} // namespace perfetto\n"); 273 header_printer.Print("\n#endif // $g$\n", "g", include_guard); 274 } 275 276 void ProtoToCpp::GenHeader(const Descriptor* msg, Printer* p) { 277 PERFETTO_ILOG("GEN %s %s", msg->name().c_str(), msg->file()->name().c_str()); 278 p->Print("\nclass PERFETTO_EXPORT $n$ {\n", "n", msg->name()); 279 p->Print(" public:\n"); 280 p->Indent(); 281 // Do a first pass to generate nested types. 282 for (int i = 0; i < msg->field_count(); i++) { 283 const FieldDescriptor* field = msg->field(i); 284 if (field->has_default_value()) { 285 PERFETTO_FATAL( 286 "Error on field %s: Explicitly declared default values are not " 287 "supported", 288 field->name().c_str()); 289 } 290 291 if (field->type() == FieldDescriptor::TYPE_ENUM) { 292 const EnumDescriptor* enum_desc = field->enum_type(); 293 p->Print("enum $n$ {\n", "n", enum_desc->name()); 294 for (int e = 0; e < enum_desc->value_count(); e++) { 295 const EnumValueDescriptor* value = enum_desc->value(e); 296 p->Print(" $n$ = $v$,\n", "n", value->name(), "v", 297 std::to_string(value->number())); 298 } 299 p->Print("};\n"); 300 } else if (field->type() == FieldDescriptor::TYPE_MESSAGE && 301 field->message_type()->file() == msg->file()) { 302 GenHeader(field->message_type(), p); 303 } 304 } 305 306 p->Print("$n$();\n", "n", msg->name()); 307 p->Print("~$n$();\n", "n", msg->name()); 308 p->Print("$n$($n$&&) noexcept;\n", "n", msg->name()); 309 p->Print("$n$& operator=($n$&&);\n", "n", msg->name()); 310 p->Print("$n$(const $n$&);\n", "n", msg->name()); 311 p->Print("$n$& operator=(const $n$&);\n", "n", msg->name()); 312 p->Print("bool operator==(const $n$&) const;\n", "n", msg->name()); 313 p->Print( 314 "bool operator!=(const $n$& other) const { return !(*this == other); }\n", 315 "n", msg->name()); 316 p->Print("\n"); 317 318 std::string proto_type = GetFwdDeclType(msg, true); 319 p->Print("// Conversion methods from/to the corresponding protobuf types.\n"); 320 p->Print("void FromProto(const $p$&);\n", "n", msg->name(), "p", proto_type); 321 p->Print("void ToProto($p$*) const;\n", "p", proto_type); 322 323 // Generate accessors. 324 for (int i = 0; i < msg->field_count(); i++) { 325 const FieldDescriptor* field = msg->field(i); 326 p->Print("\n"); 327 if (!field->is_repeated()) { 328 p->Print("$t$ $n$() const { return $n$_; }\n", "t", 329 GetCppType(field, true), "n", field->lowercase_name()); 330 if (field->type() == FieldDescriptor::TYPE_MESSAGE) { 331 p->Print("$t$* mutable_$n$() { return &$n$_; }\n", "t", 332 GetCppType(field, false), "n", field->lowercase_name()); 333 } else { 334 p->Print("void set_$n$($t$ value) { $n$_ = value; }\n", "t", 335 GetCppType(field, true), "n", field->lowercase_name()); 336 if (field->type() == FieldDescriptor::TYPE_BYTES) { 337 p->Print( 338 "void set_$n$(const void* p, size_t s) { " 339 "$n$_.assign(reinterpret_cast<const char*>(p), s); }\n", 340 "n", field->lowercase_name()); 341 } 342 } 343 } else { // is_repeated() 344 p->Print( 345 "int $n$_size() const { return static_cast<int>($n$_.size()); }\n", 346 "t", GetCppType(field, false), "n", field->lowercase_name()); 347 p->Print("const std::vector<$t$>& $n$() const { return $n$_; }\n", "t", 348 GetCppType(field, false), "n", field->lowercase_name()); 349 p->Print("std::vector<$t$>* mutable_$n$() { return &$n$_; }\n", "t", 350 GetCppType(field, false), "n", field->lowercase_name()); 351 p->Print("void clear_$n$() { $n$_.clear(); }\n", "n", 352 field->lowercase_name()); 353 p->Print("$t$* add_$n$() { $n$_.emplace_back(); return &$n$_.back(); }\n", 354 "t", GetCppType(field, false), "n", field->lowercase_name()); 355 } 356 } 357 p->Outdent(); 358 p->Print("\n private:\n"); 359 p->Indent(); 360 361 // Generate fields. 362 for (int i = 0; i < msg->field_count(); i++) { 363 const FieldDescriptor* field = msg->field(i); 364 if (!field->is_repeated()) { 365 p->Print("$t$ $n$_ = {};\n", "t", GetCppType(field, false), "n", 366 field->lowercase_name()); 367 } else { // is_repeated() 368 p->Print("std::vector<$t$> $n$_;\n", "t", GetCppType(field, false), "n", 369 field->lowercase_name()); 370 } 371 } 372 p->Print("\n"); 373 p->Print("// Allows to preserve unknown protobuf fields for compatibility\n"); 374 p->Print("// with future versions of .proto files.\n"); 375 p->Print("std::string unknown_fields_;\n"); 376 p->Outdent(); 377 p->Print("};\n\n"); 378 } 379 380 void ProtoToCpp::GenCpp(const Descriptor* msg, Printer* p, std::string prefix) { 381 p->Print("\n"); 382 std::string full_name = prefix + msg->name(); 383 p->Print("$f$::$n$() = default;\n", "f", full_name, "n", msg->name()); 384 p->Print("$f$::~$n$() = default;\n", "f", full_name, "n", msg->name()); 385 p->Print("$f$::$n$(const $f$&) = default;\n", "f", full_name, "n", 386 msg->name()); 387 p->Print("$f$& $f$::operator=(const $f$&) = default;\n", "f", full_name, "n", 388 msg->name()); 389 p->Print("$f$::$n$($f$&&) noexcept = default;\n", "f", full_name, "n", 390 msg->name()); 391 p->Print("$f$& $f$::operator=($f$&&) = default;\n", "f", full_name, "n", 392 msg->name()); 393 394 p->Print("\n"); 395 396 // Comparison operator 397 p->Print("#pragma GCC diagnostic push\n"); 398 p->Print("#pragma GCC diagnostic ignored \"-Wfloat-equal\"\n"); 399 p->Print("bool $f$::operator==(const $f$& other) const {\n", "f", full_name, 400 "n", msg->name()); 401 p->Indent(); 402 403 p->Print("return "); 404 for (int i = 0; i < msg->field_count(); i++) { 405 if (i > 0) 406 p->Print("\n && "); 407 const FieldDescriptor* field = msg->field(i); 408 p->Print("($n$_ == other.$n$_)", "n", field->name()); 409 } 410 p->Print(";"); 411 p->Outdent(); 412 p->Print("}\n"); 413 p->Print("#pragma GCC diagnostic pop\n\n"); 414 415 std::string proto_type = GetFwdDeclType(msg, true); 416 417 // Genrate the FromProto() method definition. 418 p->Print("void $f$::FromProto(const $p$& proto) {\n", "f", full_name, "p", 419 proto_type); 420 p->Indent(); 421 for (int i = 0; i < msg->field_count(); i++) { 422 p->Print("\n"); 423 const FieldDescriptor* field = msg->field(i); 424 if (!field->is_repeated()) { 425 if (field->type() == FieldDescriptor::TYPE_MESSAGE) { 426 p->Print("$n$_.FromProto(proto.$n$());\n", "n", field->name()); 427 } else { 428 p->Print( 429 "static_assert(sizeof($n$_) == sizeof(proto.$n$()), \"size " 430 "mismatch\");\n", 431 "n", field->name()); 432 p->Print("$n$_ = static_cast<decltype($n$_)>(proto.$n$());\n", "n", 433 field->name()); 434 } 435 } else { // is_repeated() 436 p->Print("$n$_.clear();\n", "n", field->name()); 437 p->Print("for (const auto& field : proto.$n$()) {\n", "n", field->name()); 438 p->Print(" $n$_.emplace_back();\n", "n", field->name()); 439 if (field->type() == FieldDescriptor::TYPE_MESSAGE) { 440 p->Print(" $n$_.back().FromProto(field);\n", "n", field->name()); 441 } else { 442 p->Print( 443 "static_assert(sizeof($n$_.back()) == sizeof(proto.$n$(0)), \"size " 444 "mismatch\");\n", 445 "n", field->name()); 446 p->Print( 447 " $n$_.back() = static_cast<decltype($n$_)::value_type>(field);\n", 448 "n", field->name()); 449 } 450 p->Print("}\n"); 451 } 452 } 453 p->Print("unknown_fields_ = proto.unknown_fields();\n"); 454 p->Outdent(); 455 p->Print("}\n\n"); 456 457 // Genrate the ToProto() method definition. 458 p->Print("void $f$::ToProto($p$* proto) const {\n", "f", full_name, "p", 459 proto_type); 460 p->Indent(); 461 p->Print("proto->Clear();\n"); 462 for (int i = 0; i < msg->field_count(); i++) { 463 p->Print("\n"); 464 const FieldDescriptor* field = msg->field(i); 465 if (!field->is_repeated()) { 466 if (field->type() == FieldDescriptor::TYPE_MESSAGE) { 467 p->Print("$n$_.ToProto(proto->mutable_$n$());\n", "n", field->name()); 468 } else { 469 p->Print( 470 "static_assert(sizeof($n$_) == sizeof(proto->$n$()), \"size " 471 "mismatch\");\n", 472 "n", field->name()); 473 p->Print("proto->set_$n$(static_cast<decltype(proto->$n$())>($n$_));\n", 474 "n", field->name()); 475 } 476 } else { // is_repeated() 477 p->Print("for (const auto& it : $n$_) {\n", "n", field->name()); 478 if (field->type() == FieldDescriptor::TYPE_MESSAGE) { 479 p->Print(" auto* entry = proto->add_$n$();\n", "n", field->name()); 480 p->Print(" it.ToProto(entry);\n"); 481 } else { 482 p->Print( 483 " proto->add_$n$(static_cast<decltype(proto->$n$(0))>(it));\n", 484 "n", field->name()); 485 p->Print( 486 "static_assert(sizeof(it) == sizeof(proto->$n$(0)), \"size " 487 "mismatch\");\n", 488 "n", field->name()); 489 } 490 p->Print("}\n"); 491 } 492 } 493 p->Print("*(proto->mutable_unknown_fields()) = unknown_fields_;\n"); 494 p->Outdent(); 495 p->Print("}\n\n"); 496 497 // Recurse into nested types. 498 for (int i = 0; i < msg->field_count(); i++) { 499 const FieldDescriptor* field = msg->field(i); 500 501 if (field->type() == FieldDescriptor::TYPE_MESSAGE && 502 field->message_type()->file() == msg->file()) { 503 std::string child_prefix = prefix + msg->name() + "::"; 504 GenCpp(field->message_type(), p, child_prefix); 505 } 506 } 507 } 508 509 int main(int argc, char** argv) { 510 if (argc <= 4) { 511 PERFETTO_ELOG( 512 "Usage: %s source.proto dir/for/header dir/for/cc include/path", 513 argv[0]); 514 return 1; 515 } 516 ProtoToCpp proto_to_cpp(argv[2], argv[3], argv[4]); 517 proto_to_cpp.Convert(argv[1]); 518 return 0; 519 } 520