blob: 1233ff93767a10f5a377145f85a1786a9a830def [file] [log] [blame]
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001/*
2 * Copyright 2014 Google Inc. All rights reserved.
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 "flatbuffers/flatc.h"
18
19#include <list>
20
21namespace flatbuffers {
22
23const char *FLATC_VERSION() { return FLATBUFFERS_VERSION(); }
24
25void FlatCompiler::ParseFile(
26 flatbuffers::Parser &parser, const std::string &filename,
27 const std::string &contents,
28 std::vector<const char *> &include_directories) const {
29 auto local_include_directory = flatbuffers::StripFileName(filename);
30 include_directories.push_back(local_include_directory.c_str());
31 include_directories.push_back(nullptr);
32 if (!parser.Parse(contents.c_str(), &include_directories[0],
33 filename.c_str())) {
34 Error(parser.error_, false, false);
35 }
36 if (!parser.error_.empty()) { Warn(parser.error_, false); }
37 include_directories.pop_back();
38 include_directories.pop_back();
39}
40
41void FlatCompiler::LoadBinarySchema(flatbuffers::Parser &parser,
42 const std::string &filename,
43 const std::string &contents) {
44 if (!parser.Deserialize(reinterpret_cast<const uint8_t *>(contents.c_str()),
Austin Schuh272c6132020-11-14 16:37:52 -080045 contents.size())) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -070046 Error("failed to load binary schema: " + filename, false, false);
47 }
48}
49
50void FlatCompiler::Warn(const std::string &warn, bool show_exe_name) const {
51 params_.warn_fn(this, warn, show_exe_name);
52}
53
54void FlatCompiler::Error(const std::string &err, bool usage,
55 bool show_exe_name) const {
56 params_.error_fn(this, err, usage, show_exe_name);
57}
58
59std::string FlatCompiler::GetUsageString(const char *program_name) const {
60 std::stringstream ss;
61 ss << "Usage: " << program_name << " [OPTION]... FILE... [-- FILE...]\n";
62 for (size_t i = 0; i < params_.num_generators; ++i) {
63 const Generator &g = params_.generators[i];
64
65 std::stringstream full_name;
Austin Schuh272c6132020-11-14 16:37:52 -080066 full_name << std::setw(16) << std::left << g.generator_opt_long;
Austin Schuhe89fa2d2019-08-14 20:24:23 -070067 const char *name = g.generator_opt_short ? g.generator_opt_short : " ";
68 const char *help = g.generator_help;
69
70 ss << " " << full_name.str() << " " << name << " " << help << ".\n";
71 }
72 // clang-format off
Austin Schuh272c6132020-11-14 16:37:52 -080073
74 // Output width
75 // 12345678901234567890123456789012345678901234567890123456789012345678901234567890
Austin Schuhe89fa2d2019-08-14 20:24:23 -070076 ss <<
Austin Schuh272c6132020-11-14 16:37:52 -080077 " -o PATH Prefix PATH to all generated files.\n"
78 " -I PATH Search for includes in the specified path.\n"
79 " -M Print make rules for generated files.\n"
80 " --version Print the version number of flatc and exit.\n"
81 " --strict-json Strict JSON: field names must be / will be quoted,\n"
82 " no trailing commas in tables/vectors.\n"
83 " --allow-non-utf8 Pass non-UTF-8 input through parser and emit nonstandard\n"
84 " \\x escapes in JSON. (Default is to raise parse error on\n"
85 " non-UTF-8 input.)\n"
86 " --natural-utf8 Output strings with UTF-8 as human-readable strings.\n"
87 " By default, UTF-8 characters are printed as \\uXXXX escapes.\n"
88 " --defaults-json Output fields whose value is the default when\n"
89 " writing JSON\n"
90 " --unknown-json Allow fields in JSON that are not defined in the\n"
91 " schema. These fields will be discared when generating\n"
92 " binaries.\n"
93 " --no-prefix Don\'t prefix enum values with the enum type in C++.\n"
94 " --scoped-enums Use C++11 style scoped and strongly typed enums.\n"
95 " also implies --no-prefix.\n"
96 " --gen-includes (deprecated), this is the default behavior.\n"
97 " If the original behavior is required (no include\n"
98 " statements) use --no-includes.\n"
99 " --no-includes Don\'t generate include statements for included\n"
100 " schemas the generated file depends on (C++ / Python).\n"
101 " --gen-mutable Generate accessors that can mutate buffers in-place.\n"
102 " --gen-onefile Generate single output file for C# and Go.\n"
103 " --gen-name-strings Generate type name functions for C++ and Rust.\n"
104 " --gen-object-api Generate an additional object-based API.\n"
105 " --gen-compare Generate operator== for object-based API types.\n"
106 " --gen-nullable Add Clang _Nullable for C++ pointer. or @Nullable for Java\n"
107 " --java-checkerframe work Add @Pure for Java.\n"
108 " --gen-generated Add @Generated annotation for Java\n"
109 " --gen-jvmstatic Add @JvmStatic annotation for Kotlin methods\n"
110 " in companion object for interop from Java to Kotlin.\n"
111 " --gen-all Generate not just code for the current schema files,\n"
112 " but for all files it includes as well.\n"
113 " If the language uses a single file for output (by default\n"
114 " the case for C++ and JS), all code will end up in this one\n"
115 " file.\n"
116 " --cpp-include Adds an #include in generated file.\n"
117 " --cpp-ptr-type T Set object API pointer type (default std::unique_ptr).\n"
118 " --cpp-str-type T Set object API string type (default std::string).\n"
119 " T::c_str(), T::length() and T::empty() must be supported.\n"
120 " The custom type also needs to be constructible from std::string\n"
121 " (see the --cpp-str-flex-ctor option to change this behavior).\n"
122 " --cpp-str-flex-ctor Don't construct custom string types by passing std::string\n"
123 " from Flatbuffers, but (char* + length).\n"
124 " --cpp-std CPP_STD Generate a C++ code using features of selected C++ standard.\n"
125 " Supported CPP_STD values:\n"
126 " * 'c++0x' - generate code compatible with old compilers;\n"
127 " * 'c++11' - use C++11 code generator (default);\n"
128 " * 'c++17' - use C++17 features in generated code (experimental).\n"
129 " --object-prefix Customise class prefix for C++ object-based API.\n"
130 " --object-suffix Customise class suffix for C++ object-based API.\n"
131 " Default value is \"T\".\n"
132 " --no-js-exports Removes Node.js style export lines in JS.\n"
133 " --goog-js-export Uses goog.exports* for closure compiler exporting in JS.\n"
134 " --es6-js-export Uses ECMAScript 6 export style lines in JS.\n"
135 " --go-namespace Generate the overrided namespace in Golang.\n"
136 " --go-import Generate the overrided import for flatbuffers in Golang\n"
137 " (default is \"github.com/google/flatbuffers/go\").\n"
138 " --raw-binary Allow binaries without file_indentifier to be read.\n"
139 " This may crash flatc given a mismatched schema.\n"
140 " --size-prefixed Input binaries are size prefixed buffers.\n"
141 " --proto Input is a .proto, translate to .fbs.\n"
142 " --proto-namespace-suffix Add this namespace to any flatbuffers generated\n"
143 " SUFFIX from protobufs.\n"
144 " --oneof-union Translate .proto oneofs to flatbuffer unions.\n"
145 " --grpc Generate GRPC interfaces for the specified languages.\n"
146 " --schema Serialize schemas instead of JSON (use with -b).\n"
147 " --bfbs-comments Add doc comments to the binary schema files.\n"
148 " --bfbs-builtins Add builtin attributes to the binary schema files.\n"
149 " --bfbs-gen-embed Generate code to embed the bfbs schema to the source.\n"
150 " --conform FILE Specify a schema the following schemas should be\n"
151 " an evolution of. Gives errors if not.\n"
152 " --conform-includes Include path for the schema given with --conform PATH\n"
153 " --filename-suffix The suffix appended to the generated file names.\n"
154 " Default is '_generated'.\n"
155 " --filename-ext The extension appended to the generated file names.\n"
156 " Default is language-specific (e.g., '.h' for C++)\n"
157 " --include-prefix Prefix this path to any generated include statements.\n"
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700158 " PATH\n"
Austin Schuh272c6132020-11-14 16:37:52 -0800159 " --keep-prefix Keep original prefix of schema include statement.\n"
160 " --no-fb-import Don't include flatbuffers import statement for TypeScript.\n"
161 " --no-ts-reexport Don't re-export imported dependencies for TypeScript.\n"
162 " --short-names Use short function names for JS and TypeScript.\n"
163 " --reflect-types Add minimal type reflection to code generation.\n"
164 " --reflect-names Add minimal type/name reflection.\n"
165 " --root-type T Select or override the default root_type\n"
Austin Schuh58b9b472020-11-25 19:12:44 -0800166 " --require-explicit-ids When parsing schemas, require explicit ids (id: x).\n"
Austin Schuh272c6132020-11-14 16:37:52 -0800167 " --force-defaults Emit default values in binary output from JSON\n"
168 " --force-empty When serializing from object API representation,\n"
169 " force strings and vectors to empty rather than null.\n"
170 " --force-empty-vectors When serializing from object API representation,\n"
171 " force vectors to empty rather than null.\n"
172 " --flexbuffers Used with \"binary\" and \"json\" options, it generates\n"
173 " data using schema-less FlexBuffers.\n"
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700174 "FILEs may be schemas (must end in .fbs), binary schemas (must end in .bfbs),\n"
175 "or JSON files (conforming to preceding schema). FILEs after the -- must be\n"
176 "binary flatbuffer format files.\n"
177 "Output files are named using the base file name of the input,\n"
178 "and written to the current directory or the path given by -o.\n"
179 "example: " << program_name << " -c -b schema1.fbs schema2.fbs data.json\n";
Austin Schuh272c6132020-11-14 16:37:52 -0800180 // 12345678901234567890123456789012345678901234567890123456789012345678901234567890
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700181 // clang-format on
182 return ss.str();
183}
184
185int FlatCompiler::Compile(int argc, const char **argv) {
186 if (params_.generators == nullptr || params_.num_generators == 0) {
187 return 0;
188 }
189
190 flatbuffers::IDLOptions opts;
191 std::string output_path;
192
193 bool any_generator = false;
194 bool print_make_rules = false;
195 bool raw_binary = false;
196 bool schema_binary = false;
197 bool grpc_enabled = false;
198 std::vector<std::string> filenames;
199 std::list<std::string> include_directories_storage;
200 std::vector<const char *> include_directories;
201 std::vector<const char *> conform_include_directories;
202 std::vector<bool> generator_enabled(params_.num_generators, false);
203 size_t binary_files_from = std::numeric_limits<size_t>::max();
204 std::string conform_to_schema;
205
206 for (int argi = 0; argi < argc; argi++) {
207 std::string arg = argv[argi];
208 if (arg[0] == '-') {
209 if (filenames.size() && arg[1] != '-')
210 Error("invalid option location: " + arg, true);
211 if (arg == "-o") {
212 if (++argi >= argc) Error("missing path following: " + arg, true);
213 output_path = flatbuffers::ConCatPathFileName(
214 flatbuffers::PosixPath(argv[argi]), "");
215 } else if (arg == "-I") {
Austin Schuh272c6132020-11-14 16:37:52 -0800216 if (++argi >= argc) Error("missing path following: " + arg, true);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700217 include_directories_storage.push_back(
218 flatbuffers::PosixPath(argv[argi]));
219 include_directories.push_back(
220 include_directories_storage.back().c_str());
221 } else if (arg == "--conform") {
Austin Schuh272c6132020-11-14 16:37:52 -0800222 if (++argi >= argc) Error("missing path following: " + arg, true);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700223 conform_to_schema = flatbuffers::PosixPath(argv[argi]);
224 } else if (arg == "--conform-includes") {
Austin Schuh272c6132020-11-14 16:37:52 -0800225 if (++argi >= argc) Error("missing path following: " + arg, true);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700226 include_directories_storage.push_back(
227 flatbuffers::PosixPath(argv[argi]));
228 conform_include_directories.push_back(
229 include_directories_storage.back().c_str());
230 } else if (arg == "--include-prefix") {
Austin Schuh272c6132020-11-14 16:37:52 -0800231 if (++argi >= argc) Error("missing path following: " + arg, true);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700232 opts.include_prefix = flatbuffers::ConCatPathFileName(
233 flatbuffers::PosixPath(argv[argi]), "");
234 } else if (arg == "--keep-prefix") {
235 opts.keep_include_path = true;
236 } else if (arg == "--strict-json") {
237 opts.strict_json = true;
238 } else if (arg == "--allow-non-utf8") {
239 opts.allow_non_utf8 = true;
240 } else if (arg == "--natural-utf8") {
241 opts.natural_utf8 = true;
242 } else if (arg == "--no-js-exports") {
243 opts.skip_js_exports = true;
244 } else if (arg == "--goog-js-export") {
245 opts.use_goog_js_export_format = true;
246 opts.use_ES6_js_export_format = false;
247 } else if (arg == "--es6-js-export") {
248 opts.use_goog_js_export_format = false;
249 opts.use_ES6_js_export_format = true;
250 } else if (arg == "--go-namespace") {
251 if (++argi >= argc) Error("missing golang namespace" + arg, true);
252 opts.go_namespace = argv[argi];
253 } else if (arg == "--go-import") {
254 if (++argi >= argc) Error("missing golang import" + arg, true);
255 opts.go_import = argv[argi];
256 } else if (arg == "--defaults-json") {
257 opts.output_default_scalars_in_json = true;
258 } else if (arg == "--unknown-json") {
259 opts.skip_unexpected_fields_in_json = true;
260 } else if (arg == "--no-prefix") {
261 opts.prefixed_enums = false;
262 } else if (arg == "--scoped-enums") {
263 opts.prefixed_enums = false;
264 opts.scoped_enums = true;
265 } else if (arg == "--no-union-value-namespacing") {
266 opts.union_value_namespacing = false;
267 } else if (arg == "--gen-mutable") {
268 opts.mutable_buffer = true;
269 } else if (arg == "--gen-name-strings") {
270 opts.generate_name_strings = true;
271 } else if (arg == "--gen-object-api") {
272 opts.generate_object_based_api = true;
273 } else if (arg == "--gen-compare") {
274 opts.gen_compare = true;
275 } else if (arg == "--cpp-include") {
Austin Schuh272c6132020-11-14 16:37:52 -0800276 if (++argi >= argc) Error("missing include following: " + arg, true);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700277 opts.cpp_includes.push_back(argv[argi]);
278 } else if (arg == "--cpp-ptr-type") {
Austin Schuh272c6132020-11-14 16:37:52 -0800279 if (++argi >= argc) Error("missing type following: " + arg, true);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700280 opts.cpp_object_api_pointer_type = argv[argi];
281 } else if (arg == "--cpp-str-type") {
Austin Schuh272c6132020-11-14 16:37:52 -0800282 if (++argi >= argc) Error("missing type following: " + arg, true);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700283 opts.cpp_object_api_string_type = argv[argi];
284 } else if (arg == "--cpp-str-flex-ctor") {
285 opts.cpp_object_api_string_flexible_constructor = true;
Austin Schuh272c6132020-11-14 16:37:52 -0800286 } else if (arg == "--no-cpp-direct-copy") {
287 opts.cpp_direct_copy = false;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700288 } else if (arg == "--gen-nullable") {
289 opts.gen_nullable = true;
Austin Schuh272c6132020-11-14 16:37:52 -0800290 } else if (arg == "--java-checkerframework") {
291 opts.java_checkerframework = true;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700292 } else if (arg == "--gen-generated") {
293 opts.gen_generated = true;
294 } else if (arg == "--object-prefix") {
Austin Schuh272c6132020-11-14 16:37:52 -0800295 if (++argi >= argc) Error("missing prefix following: " + arg, true);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700296 opts.object_prefix = argv[argi];
297 } else if (arg == "--object-suffix") {
Austin Schuh272c6132020-11-14 16:37:52 -0800298 if (++argi >= argc) Error("missing suffix following: " + arg, true);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700299 opts.object_suffix = argv[argi];
300 } else if (arg == "--gen-all") {
301 opts.generate_all = true;
302 opts.include_dependence_headers = false;
Austin Schuh272c6132020-11-14 16:37:52 -0800303 opts.reexport_ts_modules = false;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700304 } else if (arg == "--gen-includes") {
305 // Deprecated, remove this option some time in the future.
Austin Schuh272c6132020-11-14 16:37:52 -0800306 Warn("warning: --gen-includes is deprecated (it is now default)\n");
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700307 } else if (arg == "--no-includes") {
308 opts.include_dependence_headers = false;
309 } else if (arg == "--gen-onefile") {
310 opts.one_file = true;
311 } else if (arg == "--raw-binary") {
312 raw_binary = true;
313 } else if (arg == "--size-prefixed") {
314 opts.size_prefixed = true;
315 } else if (arg == "--") { // Separator between text and binary inputs.
316 binary_files_from = filenames.size();
317 } else if (arg == "--proto") {
318 opts.proto_mode = true;
Austin Schuh272c6132020-11-14 16:37:52 -0800319 } else if (arg == "--proto-namespace-suffix") {
320 if (++argi >= argc) Error("missing namespace suffix" + arg, true);
321 opts.proto_namespace_suffix = argv[argi];
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700322 } else if (arg == "--oneof-union") {
323 opts.proto_oneof_union = true;
324 } else if (arg == "--schema") {
325 schema_binary = true;
326 } else if (arg == "-M") {
327 print_make_rules = true;
328 } else if (arg == "--version") {
329 printf("flatc version %s\n", FLATC_VERSION());
330 exit(0);
331 } else if (arg == "--grpc") {
332 grpc_enabled = true;
333 } else if (arg == "--bfbs-comments") {
334 opts.binary_schema_comments = true;
335 } else if (arg == "--bfbs-builtins") {
336 opts.binary_schema_builtins = true;
Austin Schuh272c6132020-11-14 16:37:52 -0800337 } else if (arg == "--bfbs-gen-embed") {
338 opts.binary_schema_gen_embed = true;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700339 } else if (arg == "--no-fb-import") {
340 opts.skip_flatbuffers_import = true;
341 } else if (arg == "--no-ts-reexport") {
342 opts.reexport_ts_modules = false;
343 } else if (arg == "--short-names") {
344 opts.js_ts_short_names = true;
345 } else if (arg == "--reflect-types") {
346 opts.mini_reflect = IDLOptions::kTypes;
347 } else if (arg == "--reflect-names") {
348 opts.mini_reflect = IDLOptions::kTypesAndNames;
Austin Schuh58b9b472020-11-25 19:12:44 -0800349 } else if (arg == "--require-explicit-ids") {
350 opts.require_explicit_ids = true;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700351 } else if (arg == "--root-type") {
Austin Schuh272c6132020-11-14 16:37:52 -0800352 if (++argi >= argc) Error("missing type following: " + arg, true);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700353 opts.root_type = argv[argi];
Austin Schuh272c6132020-11-14 16:37:52 -0800354 } else if (arg == "--filename-suffix") {
355 if (++argi >= argc) Error("missing filename suffix: " + arg, true);
356 opts.filename_suffix = argv[argi];
357 } else if (arg == "--filename-ext") {
358 if (++argi >= argc) Error("missing filename extension: " + arg, true);
359 opts.filename_extension = argv[argi];
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700360 } else if (arg == "--force-defaults") {
361 opts.force_defaults = true;
362 } else if (arg == "--force-empty") {
Austin Schuh272c6132020-11-14 16:37:52 -0800363 opts.set_empty_strings_to_null = false;
364 opts.set_empty_vectors_to_null = false;
365 } else if (arg == "--force-empty-vectors") {
366 opts.set_empty_vectors_to_null = false;
367 } else if (arg == "--java-primitive-has-method") {
368 opts.java_primitive_has_method = true;
369 } else if (arg == "--cs-gen-json-serializer") {
370 opts.cs_gen_json_serializer = true;
371 } else if (arg == "--flexbuffers") {
372 opts.use_flexbuffers = true;
373 } else if (arg == "--gen-jvmstatic") {
374 opts.gen_jvmstatic = true;
375 } else if (arg == "--cpp-std") {
376 if (++argi >= argc)
377 Error("missing C++ standard specification" + arg, true);
378 opts.cpp_std = argv[argi];
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700379 } else {
380 for (size_t i = 0; i < params_.num_generators; ++i) {
381 if (arg == params_.generators[i].generator_opt_long ||
382 (params_.generators[i].generator_opt_short &&
383 arg == params_.generators[i].generator_opt_short)) {
384 generator_enabled[i] = true;
385 any_generator = true;
386 opts.lang_to_generate |= params_.generators[i].lang;
387 goto found;
388 }
389 }
390 Error("unknown commandline argument: " + arg, true);
391 found:;
392 }
393 } else {
394 filenames.push_back(flatbuffers::PosixPath(argv[argi]));
395 }
396 }
397
398 if (!filenames.size()) Error("missing input files", false, true);
399
400 if (opts.proto_mode) {
401 if (any_generator)
402 Error("cannot generate code directly from .proto files", true);
403 } else if (!any_generator && conform_to_schema.empty()) {
404 Error("no options: specify at least one generator.", true);
405 }
406
407 flatbuffers::Parser conform_parser;
408 if (!conform_to_schema.empty()) {
409 std::string contents;
410 if (!flatbuffers::LoadFile(conform_to_schema.c_str(), true, &contents))
411 Error("unable to load schema: " + conform_to_schema);
412
413 if (flatbuffers::GetExtension(conform_to_schema) ==
414 reflection::SchemaExtension()) {
415 LoadBinarySchema(conform_parser, conform_to_schema, contents);
416 } else {
417 ParseFile(conform_parser, conform_to_schema, contents,
418 conform_include_directories);
419 }
420 }
421
422 std::unique_ptr<flatbuffers::Parser> parser(new flatbuffers::Parser(opts));
423
424 for (auto file_it = filenames.begin(); file_it != filenames.end();
425 ++file_it) {
426 auto &filename = *file_it;
427 std::string contents;
428 if (!flatbuffers::LoadFile(filename.c_str(), true, &contents))
429 Error("unable to load file: " + filename);
430
431 bool is_binary =
432 static_cast<size_t>(file_it - filenames.begin()) >= binary_files_from;
433 auto ext = flatbuffers::GetExtension(filename);
434 auto is_schema = ext == "fbs" || ext == "proto";
435 auto is_binary_schema = ext == reflection::SchemaExtension();
436 if (is_binary) {
437 parser->builder_.Clear();
438 parser->builder_.PushFlatBuffer(
439 reinterpret_cast<const uint8_t *>(contents.c_str()),
440 contents.length());
441 if (!raw_binary) {
442 // Generally reading binaries that do not correspond to the schema
443 // will crash, and sadly there's no way around that when the binary
444 // does not contain a file identifier.
445 // We'd expect that typically any binary used as a file would have
446 // such an identifier, so by default we require them to match.
447 if (!parser->file_identifier_.length()) {
448 Error("current schema has no file_identifier: cannot test if \"" +
449 filename +
450 "\" matches the schema, use --raw-binary to read this file"
451 " anyway.");
452 } else if (!flatbuffers::BufferHasIdentifier(
Austin Schuh272c6132020-11-14 16:37:52 -0800453 contents.c_str(), parser->file_identifier_.c_str(),
454 opts.size_prefixed)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700455 Error("binary \"" + filename +
456 "\" does not have expected file_identifier \"" +
457 parser->file_identifier_ +
458 "\", use --raw-binary to read this file anyway.");
459 }
460 }
461 } else {
462 // Check if file contains 0 bytes.
Austin Schuh272c6132020-11-14 16:37:52 -0800463 if (!opts.use_flexbuffers && !is_binary_schema &&
464 contents.length() != strlen(contents.c_str())) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700465 Error("input file appears to be binary: " + filename, true);
466 }
467 if (is_schema) {
468 // If we're processing multiple schemas, make sure to start each
469 // one from scratch. If it depends on previous schemas it must do
470 // so explicitly using an include.
471 parser.reset(new flatbuffers::Parser(opts));
472 }
473 if (is_binary_schema) {
474 LoadBinarySchema(*parser.get(), filename, contents);
Austin Schuh272c6132020-11-14 16:37:52 -0800475 }
476 if (opts.use_flexbuffers) {
477 if (opts.lang_to_generate == IDLOptions::kJson) {
478 parser->flex_root_ = flexbuffers::GetRoot(
479 reinterpret_cast<const uint8_t *>(contents.c_str()),
480 contents.size());
481 } else {
482 parser->flex_builder_.Clear();
483 ParseFile(*parser.get(), filename, contents, include_directories);
484 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700485 } else {
486 ParseFile(*parser.get(), filename, contents, include_directories);
487 if (!is_schema && !parser->builder_.GetSize()) {
488 // If a file doesn't end in .fbs, it must be json/binary. Ensure we
489 // didn't just parse a schema with a different extension.
490 Error("input file is neither json nor a .fbs (schema) file: " +
491 filename,
492 true);
493 }
494 }
495 if ((is_schema || is_binary_schema) && !conform_to_schema.empty()) {
496 auto err = parser->ConformTo(conform_parser);
497 if (!err.empty()) Error("schemas don\'t conform: " + err);
498 }
Austin Schuh272c6132020-11-14 16:37:52 -0800499 if (schema_binary || opts.binary_schema_gen_embed) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700500 parser->Serialize();
Austin Schuh272c6132020-11-14 16:37:52 -0800501 }
502 if (schema_binary) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700503 parser->file_extension_ = reflection::SchemaExtension();
504 }
505 }
506
507 std::string filebase =
508 flatbuffers::StripPath(flatbuffers::StripExtension(filename));
509
510 for (size_t i = 0; i < params_.num_generators; ++i) {
511 parser->opts.lang = params_.generators[i].lang;
512 if (generator_enabled[i]) {
513 if (!print_make_rules) {
514 flatbuffers::EnsureDirExists(output_path);
515 if ((!params_.generators[i].schema_only ||
516 (is_schema || is_binary_schema)) &&
517 !params_.generators[i].generate(*parser.get(), output_path,
518 filebase)) {
519 Error(std::string("Unable to generate ") +
520 params_.generators[i].lang_name + " for " + filebase);
521 }
522 } else {
Austin Schuh272c6132020-11-14 16:37:52 -0800523 if (params_.generators[i].make_rule == nullptr) {
524 Error(std::string("Cannot generate make rule for ") +
525 params_.generators[i].lang_name);
526 } else {
527 std::string make_rule = params_.generators[i].make_rule(
528 *parser.get(), output_path, filename);
529 if (!make_rule.empty())
530 printf("%s\n",
531 flatbuffers::WordWrap(make_rule, 80, " ", " \\").c_str());
532 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700533 }
534 if (grpc_enabled) {
535 if (params_.generators[i].generateGRPC != nullptr) {
536 if (!params_.generators[i].generateGRPC(*parser.get(), output_path,
537 filebase)) {
538 Error(std::string("Unable to generate GRPC interface for") +
539 params_.generators[i].lang_name);
540 }
541 } else {
542 Warn(std::string("GRPC interface generator not implemented for ") +
543 params_.generators[i].lang_name);
544 }
545 }
546 }
547 }
548
549 if (!opts.root_type.empty()) {
550 if (!parser->SetRootType(opts.root_type.c_str()))
551 Error("unknown root type: " + opts.root_type);
552 else if (parser->root_struct_def_->fixed)
553 Error("root type must be a table");
554 }
555
556 if (opts.proto_mode) GenerateFBS(*parser.get(), output_path, filebase);
557
558 // We do not want to generate code for the definitions in this file
559 // in any files coming up next.
560 parser->MarkGenerated();
561 }
562 return 0;
563}
564
565} // namespace flatbuffers