diff options
author | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-19 16:50:52 +0000 |
---|---|---|
committer | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-19 16:50:52 +0000 |
commit | e9bf4fcb470f7220306c39827fc3fd9be0a27741 (patch) | |
tree | 59d2c4de7ab1964d6c421dd014b629ce9bd961e1 /tools/gn/file_template.cc | |
parent | 252e6603f3012cdc8de4a212999ef62660769be7 (diff) | |
download | chromium_src-e9bf4fcb470f7220306c39827fc3fd9be0a27741.zip chromium_src-e9bf4fcb470f7220306c39827fc3fd9be0a27741.tar.gz chromium_src-e9bf4fcb470f7220306c39827fc3fd9be0a27741.tar.bz2 |
Add directory extraction to GN path handling.
Some of the mojo templates want to put generated files in the directory
corresponding to the source file, rather than the directory containing the
BUILD file. Previously, this required putting the BUILD files in the same
directory.
This patch adds the ability to specify the generated file directory
corresponding to the input file in the action_foreach file templates so this
can be expressed naturally.
For parity, it also adds qquerying for this information via get_path_info.
BUG=
R=cjhopman@chromium.org
Review URL: https://codereview.chromium.org/334333005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@278402 0039d316-1c4b-4281-b951-d872f2087c98
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 } } |