Index: tools/gn/file_template.cc |
diff --git a/tools/gn/file_template.cc b/tools/gn/file_template.cc |
deleted file mode 100644 |
index 6ad37e5be9c7f296dac56306d23df40d1177ea2d..0000000000000000000000000000000000000000 |
--- a/tools/gn/file_template.cc |
+++ /dev/null |
@@ -1,419 +0,0 @@ |
-// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "tools/gn/file_template.h" |
- |
-#include <algorithm> |
-#include <iostream> |
- |
-#include "tools/gn/escape.h" |
-#include "tools/gn/filesystem_utils.h" |
-#include "tools/gn/string_utils.h" |
-#include "tools/gn/target.h" |
- |
-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" |
- "\n" |
- " Source expansion is used for the action_foreach and copy target types\n" |
- " to map source file names to output file names or arguments.\n" |
- "\n" |
- " To perform source expansion in the outputs, GN maps every entry in the\n" |
- " sources to every entry in the outputs list, producing the cross\n" |
- " product of all combinations, expanding placeholders (see below).\n" |
- "\n" |
- " Source expansion in the args works similarly, but performing the\n" |
- " placeholder substitution produces a different set of arguments for\n" |
- " each invocation of the script.\n" |
- "\n" |
- " If no placeholders are found, the outputs or args list will be treated\n" |
- " as a static list of literal file names that do not depend on the\n" |
- " sources.\n" |
- "\n" |
- " See \"gn help copy\" and \"gn help action_foreach\" for more on how\n" |
- " this is applied.\n" |
- "\n" |
- "Placeholders\n" |
- "\n" |
- " {{source}}\n" |
- " The name of the source file including directory (*). This will\n" |
- " generally be used for specifying inputs to a script in the\n" |
- " \"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.\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.\n" |
- " \"//foo/bar/baz.txt\" => \"baz\"\n" |
- "\n" |
- " {{source_dir}}\n" |
- " The directory (*) containing the source file with no\n" |
- " 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. This value will always\n" |
- " be the same, regardless of whether it appears in the \"outputs\"\n" |
- " or \"args\" section.\n" |
- " \"//foo/bar/baz.txt\" => \"foo/bar\"\n" |
- "\n" |
- " {{source_gen_dir}}\n" |
- " The generated file directory (*) corresponding to the source\n" |
- " file's path. This will be different than the target's generated\n" |
- " file directory if the source file is in a different directory\n" |
- " than the BUILD.gn file.\n" |
- " \"//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.\n" |
- " \"//foo/bar/baz.txt\" => \"obj/foo/bar\"\n" |
- "\n" |
- "(*) Note on directories\n" |
- "\n" |
- " Paths containing directories (except the source_root_relative_dir)\n" |
- " will be different depending on what context the expansion is evaluated\n" |
- " in. Generally it should \"just work\" but it means you can't\n" |
- " concatenate strings containing these values with reasonable results.\n" |
- "\n" |
- " Details: source expansions can be used in the \"outputs\" variable,\n" |
- " the \"args\" variable, and in calls to \"process_file_template\". The\n" |
- " \"args\" are passed to a script which is run from the build directory,\n" |
- " so these directories will relative to the build directory for the\n" |
- " script to find. In the other cases, the directories will be source-\n" |
- " absolute (begin with a \"//\") because the results of those expansions\n" |
- " will be handled by GN internally.\n" |
- "\n" |
- "Examples\n" |
- "\n" |
- " Non-varying outputs:\n" |
- " action(\"hardcoded_outputs\") {\n" |
- " sources = [ \"input1.idl\", \"input2.idl\" ]\n" |
- " outputs = [ \"$target_out_dir/output1.dat\",\n" |
- " \"$target_out_dir/output2.dat\" ]\n" |
- " }\n" |
- " The outputs in this case will be the two literal files given.\n" |
- "\n" |
- " Varying outputs:\n" |
- " action_foreach(\"varying_outputs\") {\n" |
- " sources = [ \"input1.idl\", \"input2.idl\" ]\n" |
- " outputs = [ \"{{source_gen_dir}}/{{source_name_part}}.h\",\n" |
- " \"{{source_gen_dir}}/{{source_name_part}}.cc\" ]\n" |
- " }\n" |
- " Performing source expansion will result in the following output names:\n" |
- " //out/Debug/obj/mydirectory/input1.h\n" |
- " //out/Debug/obj/mydirectory/input1.cc\n" |
- " //out/Debug/obj/mydirectory/input2.h\n" |
- " //out/Debug/obj/mydirectory/input2.cc\n"; |
- |
-FileTemplate::FileTemplate(const Settings* settings, |
- const Value& t, |
- OutputStyle output_style, |
- const SourceDir& relative_to, |
- Err* err) |
- : settings_(settings), |
- output_style_(output_style), |
- relative_to_(relative_to), |
- has_substitutions_(false) { |
- std::fill(types_required_, &types_required_[Subrange::NUM_TYPES], false); |
- ParseInput(t, err); |
-} |
- |
-FileTemplate::FileTemplate(const Settings* settings, |
- const std::vector<std::string>& t, |
- OutputStyle output_style, |
- const SourceDir& relative_to) |
- : settings_(settings), |
- output_style_(output_style), |
- relative_to_(relative_to), |
- 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 Settings* settings, |
- const std::vector<SourceFile>& t, |
- OutputStyle output_style, |
- const SourceDir& relative_to) |
- : settings_(settings), |
- output_style_(output_style), |
- relative_to_(relative_to), |
- 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()); |
-} |
- |
-FileTemplate::~FileTemplate() { |
-} |
- |
-// static |
-FileTemplate FileTemplate::GetForTargetOutputs(const Target* target) { |
- const std::vector<std::string>& outputs = target->action_values().outputs(); |
- std::vector<std::string> output_template_args; |
- for (size_t i = 0; i < outputs.size(); i++) |
- output_template_args.push_back(outputs[i]); |
- return FileTemplate(target->settings(), output_template_args, |
- OUTPUT_ABSOLUTE, SourceDir()); |
-} |
- |
-bool FileTemplate::IsTypeUsed(Subrange::Type type) const { |
- DCHECK(type > Subrange::LITERAL && type < Subrange::NUM_TYPES); |
- return types_required_[type]; |
-} |
- |
-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(settings_, source, |
- static_cast<Subrange::Type>(i), |
- output_style_, relative_to_); |
- } |
- } |
- |
- size_t first_output_index = output->size(); |
- output->resize(output->size() + templates_.container().size()); |
- for (size_t template_i = 0; |
- template_i < templates_.container().size(); template_i++) { |
- const Template& t = templates_[template_i]; |
- std::string& cur_output = (*output)[first_output_index + template_i]; |
- for (size_t subrange_i = 0; subrange_i < t.container().size(); |
- subrange_i++) { |
- if (t[subrange_i].type == Subrange::LITERAL) |
- cur_output.append(t[subrange_i].literal); |
- else |
- cur_output.append(subst[t[subrange_i].type]); |
- } |
- } |
-} |
- |
-void FileTemplate::WriteWithNinjaExpansions(std::ostream& out) const { |
- EscapeOptions escape_options; |
- escape_options.mode = ESCAPE_NINJA_COMMAND; |
- escape_options.inhibit_quoting = true; |
- |
- for (size_t template_i = 0; |
- template_i < templates_.container().size(); template_i++) { |
- out << " "; // Separate args with spaces. |
- |
- const Template& t = templates_[template_i]; |
- |
- // Escape each subrange into a string. Since we're writing out Ninja |
- // variables, we can't quote the whole thing, so we write in pieces, only |
- // escaping the literals, and then quoting the whole thing at the end if |
- // necessary. |
- bool needs_quoting = false; |
- std::string item_str; |
- for (size_t subrange_i = 0; subrange_i < t.container().size(); |
- subrange_i++) { |
- if (t[subrange_i].type == Subrange::LITERAL) { |
- bool cur_needs_quoting = false; |
- item_str.append(EscapeString(t[subrange_i].literal, escape_options, |
- &cur_needs_quoting)); |
- needs_quoting |= cur_needs_quoting; |
- } else { |
- // Don't escape this since we need to preserve the $. |
- item_str.append("${"); |
- item_str.append(GetNinjaVariableNameForType(t[subrange_i].type)); |
- item_str.append("}"); |
- } |
- } |
- |
- if (needs_quoting || item_str.empty()) { |
- // Need to shell quote the whole string. We also need to quote empty |
- // strings or it would be impossible to pass "" as a command-line |
- // argument. |
- out << '"' << item_str << '"'; |
- } else { |
- out << item_str; |
- } |
- } |
-} |
- |
-void FileTemplate::WriteNinjaVariablesForSubstitution( |
- std::ostream& out, |
- 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(settings_, source, type, output_style_, relative_to_), |
- escape_options); |
- out << std::endl; |
- } |
- } |
-} |
- |
-// static |
-const char* FileTemplate::GetNinjaVariableNameForType(Subrange::Type type) { |
- switch (type) { |
- case Subrange::SOURCE: |
- return "source"; |
- case Subrange::NAME_PART: |
- 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(); |
- } |
- return ""; |
-} |
- |
-// static |
-std::string FileTemplate::GetSubstitution(const Settings* settings, |
- const SourceFile& source, |
- Subrange::Type type, |
- OutputStyle output_style, |
- const SourceDir& relative_to) { |
- std::string to_rebase; |
- switch (type) { |
- case Subrange::SOURCE: |
- if (source.is_system_absolute()) |
- return source.value(); |
- to_rebase = source.value(); |
- break; |
- |
- case Subrange::NAME_PART: |
- return FindFilenameNoExtension(&source.value()).as_string(); |
- |
- case Subrange::FILE_PART: |
- return source.GetName(); |
- |
- case Subrange::SOURCE_DIR: |
- if (source.is_system_absolute()) |
- return DirectoryWithNoLastSlash(source.GetDir()); |
- to_rebase = DirectoryWithNoLastSlash(source.GetDir()); |
- break; |
- |
- 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: |
- to_rebase = DirectoryWithNoLastSlash( |
- GetGenDirForSourceDir(settings, source.GetDir())); |
- break; |
- |
- case Subrange::SOURCE_OUT_DIR: |
- to_rebase = DirectoryWithNoLastSlash( |
- GetOutputDirForSourceDir(settings, source.GetDir())); |
- break; |
- |
- default: |
- NOTREACHED(); |
- return std::string(); |
- } |
- |
- // If we get here, the result is a path that should be made relative or |
- // absolute according to the output_style. Other cases (just file name or |
- // extension extraction) will have been handled via early return above. |
- if (output_style == OUTPUT_ABSOLUTE) |
- return to_rebase; |
- return RebaseSourceAbsolutePath(to_rebase, relative_to); |
-} |
- |
-void FileTemplate::ParseInput(const Value& value, Err* err) { |
- switch (value.type()) { |
- case Value::STRING: |
- ParseOneTemplateString(value.string_value()); |
- break; |
- case Value::LIST: |
- for (size_t i = 0; i < value.list_value().size(); i++) { |
- if (!value.list_value()[i].VerifyTypeIs(Value::STRING, err)) |
- return; |
- ParseOneTemplateString(value.list_value()[i].string_value()); |
- } |
- break; |
- default: |
- *err = Err(value, "File template must be a string or list.", |
- "A sarcastic comment about your skills goes here."); |
- } |
-} |
- |
-void FileTemplate::ParseOneTemplateString(const std::string& str) { |
- templates_.container().resize(templates_.container().size() + 1); |
- Template& t = templates_[templates_.container().size() - 1]; |
- |
- size_t cur = 0; |
- while (true) { |
- size_t next = str.find("{{", cur); |
- |
- // Pick up everything from the previous spot to here as a literal. |
- if (next == std::string::npos) { |
- if (cur != str.size()) |
- t.container().push_back(Subrange(Subrange::LITERAL, str.substr(cur))); |
- break; |
- } else if (next > cur) { |
- t.container().push_back( |
- 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_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 |
- } |
-} |