diff options
Diffstat (limited to 'tools/gn/file_template.cc')
-rw-r--r-- | tools/gn/file_template.cc | 189 |
1 files changed, 127 insertions, 62 deletions
diff --git a/tools/gn/file_template.cc b/tools/gn/file_template.cc index b00eb39..2809920 100644 --- a/tools/gn/file_template.cc +++ b/tools/gn/file_template.cc @@ -15,6 +15,10 @@ const char FileTemplate::kSource[] = "{{source}}"; const char FileTemplate::kSourceNamePart[] = "{{source_name_part}}"; const char FileTemplate::kSourceFilePart[] = "{{source_file_part}}"; +const char FileTemplate::kSourceDir[] = "{{source_dir}}"; +const char FileTemplate::kRootRelDir[] = "{{source_root_relative_dir}}"; +const char FileTemplate::kSourceGenDir[] = "{{source_gen_dir}}"; +const char FileTemplate::kSourceOutDir[] = "{{source_out_dir}}"; const char kSourceExpansion_Help[] = "How Source Expansion Works\n" @@ -44,17 +48,47 @@ const char kSourceExpansion_Help[] = " directory (which is the current directory when running compilers\n" " and scripts). This will generally be used for specifying inputs\n" " to a script in the \"args\" variable.\n" + " \"//foo/bar/baz.txt\" => \"../../foo/bar/baz.txt\"\n" "\n" " {{source_file_part}}\n" - " The file part of the source including the extension. For the\n" - " source \"foo/bar.txt\" the source file part will be \"bar.txt\".\n" + " The file part of the source including the extension.\n" + " \"//foo/bar/baz.txt\" => \"baz.txt\"\n" "\n" " {{source_name_part}}\n" " The filename part of the source file with no directory or\n" " extension. This will generally be used for specifying a\n" " transformation from a soruce file to a destination file with the\n" - " same name but different extension. For the source \"foo/bar.txt\"\n" - " the source name part will be \"bar\".\n" + " same name but different extension.\n" + " \"//foo/bar/baz.txt\" => \"baz\"\n" + "\n" + " {{source_dir}}\n" + " The directory containing the source file, relative to the build\n" + " directory, with no trailing slash.\n" + " \"//foo/bar/baz.txt\" => \"../../foo/bar\"\n" + "\n" + " {{source_root_relative_dir}}\n" + " The path to the source file's directory relative to the source\n" + " root, with no leading \"//\" or trailing slashes. If the path is\n" + " system-absolute, (beginning in a single slash) this will just\n" + " return the path with no trailing slash.\n" + " \"//foo/bar/baz.txt\" => \"foo/bar\"\n" + "\n" + " {{source_gen_dir}}\n" + " The generated file directory corresponding to the source file's\n" + " path, relative to the build directory. This will be different than\n" + " the target's generated file directory if the source file is in a\n" + " different directory than the build.gn file. If the input path is\n" + " system absolute, this will return the root generated file\n" + " directory." + " \"//foo/bar/baz.txt\" => \"gen/foo/bar\"\n" + "\n" + " {{source_out_dir}}\n" + " The object file directory corresponding to the source file's\n" + " path, relative to the build directory. this us be different than\n" + " the target's out directory if the source file is in a different\n" + " directory than the build.gn file. if the input path is system\n" + " absolute, this will return the root generated file directory.\n" + " \"//foo/bar/baz.txt\" => \"obj/foo/bar\"\n" "\n" "Examples\n" "\n" @@ -78,21 +112,26 @@ const char kSourceExpansion_Help[] = " //out/Debug/obj/mydirectory/input2.h\n" " //out/Debug/obj/mydirectory/input2.cc\n"; -FileTemplate::FileTemplate(const Value& t, Err* err) - : has_substitutions_(false) { +FileTemplate::FileTemplate(const Settings* settings, const Value& t, Err* err) + : settings_(settings), + has_substitutions_(false) { std::fill(types_required_, &types_required_[Subrange::NUM_TYPES], false); ParseInput(t, err); } -FileTemplate::FileTemplate(const std::vector<std::string>& t) - : has_substitutions_(false) { +FileTemplate::FileTemplate(const Settings* settings, + const std::vector<std::string>& t) + : settings_(settings), + has_substitutions_(false) { std::fill(types_required_, &types_required_[Subrange::NUM_TYPES], false); for (size_t i = 0; i < t.size(); i++) ParseOneTemplateString(t[i]); } -FileTemplate::FileTemplate(const std::vector<SourceFile>& t) - : has_substitutions_(false) { +FileTemplate::FileTemplate(const Settings* settings, + const std::vector<SourceFile>& t) + : settings_(settings), + has_substitutions_(false) { std::fill(types_required_, &types_required_[Subrange::NUM_TYPES], false); for (size_t i = 0; i < t.size(); i++) ParseOneTemplateString(t[i].value()); @@ -107,7 +146,7 @@ FileTemplate FileTemplate::GetForTargetOutputs(const Target* target) { std::vector<std::string> output_template_args; for (size_t i = 0; i < outputs.size(); i++) output_template_args.push_back(outputs[i].value()); - return FileTemplate(output_template_args); + return FileTemplate(target->settings(), output_template_args); } bool FileTemplate::IsTypeUsed(Subrange::Type type) const { @@ -115,37 +154,16 @@ bool FileTemplate::IsTypeUsed(Subrange::Type type) const { return types_required_[type]; } -void FileTemplate::Apply(const Value& sources, - const ParseNode* origin, - std::vector<Value>* dest, - Err* err) const { - if (!sources.VerifyTypeIs(Value::LIST, err)) - return; - dest->reserve(sources.list_value().size() * templates_.container().size()); - - // Temporary holding place, allocate outside to re-use- buffer. - std::vector<std::string> string_output; - - const std::vector<Value>& sources_list = sources.list_value(); - for (size_t i = 0; i < sources_list.size(); i++) { - string_output.clear(); - if (!sources_list[i].VerifyTypeIs(Value::STRING, err)) - return; - - ApplyString(sources_list[i].string_value(), &string_output); - for (size_t out_i = 0; out_i < string_output.size(); out_i++) - dest->push_back(Value(origin, string_output[out_i])); - } -} - -void FileTemplate::ApplyString(const std::string& str, - std::vector<std::string>* output) const { +void FileTemplate::Apply(const SourceFile& source, + std::vector<std::string>* output) const { // Compute all substitutions needed so we can just do substitutions below. // We skip the LITERAL one since that varies each time. std::string subst[Subrange::NUM_TYPES]; for (int i = 1; i < Subrange::NUM_TYPES; i++) { - if (types_required_[i]) - subst[i] = GetSubstitution(str, static_cast<Subrange::Type>(i)); + if (types_required_[i]) { + subst[i] = + GetSubstitution(settings_, source, static_cast<Subrange::Type>(i)); + } } size_t first_output_index = output->size(); @@ -209,13 +227,15 @@ void FileTemplate::WriteWithNinjaExpansions(std::ostream& out) const { void FileTemplate::WriteNinjaVariablesForSubstitution( std::ostream& out, - const std::string& source, + const Settings* settings, + const SourceFile& source, const EscapeOptions& escape_options) const { for (int i = 1; i < Subrange::NUM_TYPES; i++) { if (types_required_[i]) { Subrange::Type type = static_cast<Subrange::Type>(i); out << " " << GetNinjaVariableNameForType(type) << " = "; - EscapeStringToStream(out, GetSubstitution(source, type), escape_options); + EscapeStringToStream(out, GetSubstitution(settings, source, type), + escape_options); out << std::endl; } } @@ -230,6 +250,15 @@ const char* FileTemplate::GetNinjaVariableNameForType(Subrange::Type type) { return "source_name_part"; case Subrange::FILE_PART: return "source_file_part"; + case Subrange::SOURCE_DIR: + return "source_dir"; + case Subrange::ROOT_RELATIVE_DIR: + return "source_root_rel_dir"; + case Subrange::SOURCE_GEN_DIR: + return "source_gen_dir"; + case Subrange::SOURCE_OUT_DIR: + return "source_out_dir"; + default: NOTREACHED(); } @@ -237,15 +266,47 @@ const char* FileTemplate::GetNinjaVariableNameForType(Subrange::Type type) { } // static -std::string FileTemplate::GetSubstitution(const std::string& source, +std::string FileTemplate::GetSubstitution(const Settings* settings, + const SourceFile& source, Subrange::Type type) { switch (type) { case Subrange::SOURCE: - return source; + if (source.is_system_absolute()) + return source.value(); + return RebaseSourceAbsolutePath(source.value(), + settings->build_settings()->build_dir()); + case Subrange::NAME_PART: - return FindFilenameNoExtension(&source).as_string(); + return FindFilenameNoExtension(&source.value()).as_string(); + case Subrange::FILE_PART: - return FindFilename(&source).as_string(); + return source.GetName(); + + case Subrange::SOURCE_DIR: + if (source.is_system_absolute()) + return DirectoryWithNoLastSlash(source.GetDir()); + return RebaseSourceAbsolutePath( + DirectoryWithNoLastSlash(source.GetDir()), + settings->build_settings()->build_dir()); + + case Subrange::ROOT_RELATIVE_DIR: + if (source.is_system_absolute()) + return DirectoryWithNoLastSlash(source.GetDir()); + return RebaseSourceAbsolutePath( + DirectoryWithNoLastSlash(source.GetDir()), SourceDir("//")); + + case Subrange::SOURCE_GEN_DIR: + return RebaseSourceAbsolutePath( + DirectoryWithNoLastSlash( + GetGenDirForSourceDir(settings, source.GetDir())), + settings->build_settings()->build_dir()); + + case Subrange::SOURCE_OUT_DIR: + return RebaseSourceAbsolutePath( + DirectoryWithNoLastSlash( + GetOutputDirForSourceDir(settings, source.GetDir())), + settings->build_settings()->build_dir()); + default: NOTREACHED(); } @@ -288,30 +349,34 @@ void FileTemplate::ParseOneTemplateString(const std::string& str) { Subrange(Subrange::LITERAL, str.substr(cur, next - cur))); } + // Given the name of the string constant and enum for a template parameter, + // checks for it and stores it. Writing this as a function requires passing + // the entire state of this function as arguments, so this actually ends + // up being more clear. + #define IF_MATCH_THEN_STORE(const_name, enum_name) \ + if (str.compare(next, arraysize(const_name) - 1, const_name) == 0) { \ + t.container().push_back(Subrange(Subrange::enum_name)); \ + types_required_[Subrange::enum_name] = true; \ + has_substitutions_ = true; \ + cur = next + arraysize(const_name) - 1; \ + } + // Decode the template param. - if (str.compare(next, arraysize(kSource) - 1, kSource) == 0) { - t.container().push_back(Subrange(Subrange::SOURCE)); - types_required_[Subrange::SOURCE] = true; - has_substitutions_ = true; - cur = next + arraysize(kSource) - 1; - } else if (str.compare(next, arraysize(kSourceNamePart) - 1, - kSourceNamePart) == 0) { - t.container().push_back(Subrange(Subrange::NAME_PART)); - types_required_[Subrange::NAME_PART] = true; - has_substitutions_ = true; - cur = next + arraysize(kSourceNamePart) - 1; - } else if (str.compare(next, arraysize(kSourceFilePart) - 1, - kSourceFilePart) == 0) { - t.container().push_back(Subrange(Subrange::FILE_PART)); - types_required_[Subrange::FILE_PART] = true; - has_substitutions_ = true; - cur = next + arraysize(kSourceFilePart) - 1; - } else { + IF_MATCH_THEN_STORE(kSource, SOURCE) + else IF_MATCH_THEN_STORE(kSourceNamePart, NAME_PART) + else IF_MATCH_THEN_STORE(kSourceFilePart, FILE_PART) + else IF_MATCH_THEN_STORE(kSourceDir, SOURCE_DIR) + else IF_MATCH_THEN_STORE(kRootRelDir, ROOT_RELATIVE_DIR) + else IF_MATCH_THEN_STORE(kSourceGenDir, SOURCE_GEN_DIR) + else IF_MATCH_THEN_STORE(kSourceOutDir, SOURCE_OUT_DIR) + else { // If it's not a match, treat it like a one-char literal (this will be // rare, so it's not worth the bother to add to the previous literal) so // we can keep going. t.container().push_back(Subrange(Subrange::LITERAL, "{")); cur = next + 1; } + + #undef IF_MATCH_THEN_STORE } } |