diff --git a/docs/source/IntermediateRepresentation.md b/docs/source/IntermediateRepresentation.md index f5c302a7f..f4eb07539 100644 --- a/docs/source/IntermediateRepresentation.md +++ b/docs/source/IntermediateRepresentation.md @@ -13,6 +13,9 @@ There are some quirks: field of `Schema`. These mark the presence of new, backwards incompatible, schema features. Code generators must error if generating a schema with unrecognized advanced features. +- Filenames are relative to a "project root" denoted by "//" in the path. This + may be specified in flatc with `--bfbs-filenames=$PROJECT_ROOT`, or it will be + inferred to be the directory containing the first provided schema file. ## Invocation diff --git a/src/flatc.cpp b/src/flatc.cpp index 5bed461db..9afca6881 100644 --- a/src/flatc.cpp +++ b/src/flatc.cpp @@ -149,8 +149,11 @@ std::string FlatCompiler::GetUsageString(const char *program_name) const { " --oneof-union Translate .proto oneofs to flatbuffer unions.\n" " --grpc Generate GRPC interfaces for the specified languages.\n" " --schema Serialize schemas instead of JSON (use with -b).\n" - " --bfbs-filenames PATH Adds declaration filenames, relative to PATH and prefixed with" - " `//`, to the binary schema.\n" + " --bfbs-filenames PATH Sets the root path where reflection filenames in \n" + " reflection.fbs are relative to. The 'root' is denoted with \n" + " `//`. E.g. if PATH=/a/b/c \n then /a/d/e.fbs will be serialized\n" + " as //../d/e.fbs. (PATH defaults to the directory of the first\n" + " provided schema file.)\n" " --bfbs-comments Add doc comments to the binary schema files.\n" " --bfbs-builtins Add builtin attributes to the binary schema files.\n" " --bfbs-gen-embed Generate code to embed the bfbs schema to the source.\n" @@ -444,6 +447,9 @@ int FlatCompiler::Compile(int argc, const char **argv) { static_cast(file_it - filenames.begin()) >= binary_files_from; auto ext = flatbuffers::GetExtension(filename); const bool is_schema = ext == "fbs" || ext == "proto"; + if (is_schema && opts.project_root.empty()) { + opts.project_root = StripFileName(filename); + } const bool is_binary_schema = ext == reflection::SchemaExtension(); if (is_binary) { parser->builder_.Clear(); diff --git a/src/util.cpp b/src/util.cpp index 464c128b2..1a2b5f091 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -225,20 +225,29 @@ std::string RelativeToRootPath(const std::string &project, std::string absolute_project = PosixPath(AbsolutePath(project)); if (absolute_project.back() != '/') absolute_project += "/"; std::string absolute_filepath = PosixPath(AbsolutePath(filepath)); - if (absolute_filepath.size() < absolute_project.size() || - absolute_filepath.substr(0, absolute_project.size()) != - absolute_project) { - printf( - "The --bfbs-filenames directory must contain all files and included " - "files.\n"); - printf("project: %s\n", project.c_str()); - printf("filepath: %s\n", filepath.c_str()); - printf("absolute_project: %s\n", absolute_project.c_str()); - printf("absolute_filepath:%s\n", absolute_filepath.c_str()); - FLATBUFFERS_ASSERT(0); + + // Find the first character where they disagree. + // The previous directory is the lowest common ancestor; + const char *a = absolute_project.c_str(); + const char *b = absolute_filepath.c_str(); + size_t common_prefix_len = 0; + while (*a != '\0' && *b != '\0' && *a == *b) { + if (*a == '/') common_prefix_len = a - absolute_project.c_str(); + a++; + b++; } - const std::string relpath = absolute_filepath.substr(absolute_project.size()); - return "//" + relpath; + // the number of ../ to prepend to b depends on the number of remaining + // directories in A. + const char *suffix = absolute_project.c_str() + common_prefix_len; + size_t num_up = 0; + while (*suffix != '\0') + if (*suffix++ == '/') num_up++; + num_up--; // last one is known to be '/'. + std::string result = "//"; + for (size_t i = 0; i < num_up; i++) result += "../"; + result += absolute_filepath.substr(common_prefix_len + 1); + + return result; } // Locale-independent code. diff --git a/tests/test.cpp b/tests/test.cpp index ce9ce6706..6576a10e2 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -1339,7 +1339,6 @@ void ParseProtoTestWithIncludes() { flatbuffers::IDLOptions opts; opts.include_dependence_headers = true; opts.proto_mode = true; - opts.project_root = test_data_path; // Parse proto. flatbuffers::Parser parser(opts); @@ -1357,9 +1356,7 @@ void ParseProtoTestWithIncludes() { auto import_fbs = flatbuffers::GenerateFBS(import_parser, "test"); // Ensure generated file is parsable. - flatbuffers::IDLOptions opts2; - opts2.project_root = protopath; - flatbuffers::Parser parser2(opts2); + flatbuffers::Parser parser2; // Since `imported.fbs` isn't in the filesystem AbsolutePath can't figure it // out by itself. We manually construct it so Parser works. std::string imported_fbs = flatbuffers::PosixPath(