1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef TOOLS_GN_FILE_TEMPLATE_H_ 6 #define TOOLS_GN_FILE_TEMPLATE_H_ 7 8 #include <iosfwd> 9 10 #include "base/basictypes.h" 11 #include "base/containers/stack_container.h" 12 #include "tools/gn/err.h" 13 #include "tools/gn/value.h" 14 15 struct EscapeOptions; 16 class ParseNode; 17 class Target; 18 19 extern const char kSourceExpansion_Help[]; 20 21 // A FileTemplate object implements source expansion for a given "template" 22 // (either outputs or args, depending on the target type). 23 // 24 // There are two ways you can use this. You can make a template and then 25 // apply a source to it to get a list of outputs manually. Or you can do the 26 // actual substitution in Ninja, writing the arguments in a rule and using 27 // variables in build statements to invoke the rule with the right 28 // substitutions. 29 class FileTemplate { 30 public: 31 struct Subrange { 32 enum Type { 33 LITERAL = 0, 34 35 // {{source}} -> expands to be the source file name relative to the build 36 // root dir. 37 SOURCE, 38 39 // {{source_name_part}} -> file name without extension or directory. 40 // Maps "foo/bar.txt" to "bar". 41 NAME_PART, 42 43 // {{source_file_part}} -> file name including extension but no directory. 44 // Maps "foo/bar.txt" to "bar.txt". 45 FILE_PART, 46 47 NUM_TYPES // Must be last 48 }; 49 Subrange(Type t, const std::string& l = std::string()) typeSubrange50 : type(t), 51 literal(l) { 52 } 53 54 Type type; 55 56 // When type_ == LITERAL, this specifies the literal. 57 std::string literal; 58 }; 59 60 // Constructs a template from the given value. On error, the err will be 61 // set. In this case you should not use this object. 62 FileTemplate(const Value& t, Err* err); 63 FileTemplate(const std::vector<std::string>& t); 64 ~FileTemplate(); 65 66 // Returns an output template representing the given target's script 67 // outputs. 68 static FileTemplate GetForTargetOutputs(const Target* target); 69 70 // Returns true if the given substitution type is used by this template. 71 bool IsTypeUsed(Subrange::Type type) const; 72 73 // Returns true if there are any substitutions. has_substitutions()74 bool has_substitutions() const { return has_substitutions_; } 75 76 // Applies this template to the given list of sources, appending all 77 // results to the given dest list. The sources must be a list for the 78 // one that takes a value as an input, otherwise the given error will be set. 79 void Apply(const Value& sources, 80 const ParseNode* origin, 81 std::vector<Value>* dest, 82 Err* err) const; 83 void ApplyString(const std::string& input, 84 std::vector<std::string>* output) const; 85 86 // Writes a string representing the template with Ninja variables for the 87 // substitutions, and the literals escaped for Ninja consumption. 88 // 89 // For example, if the input is "foo{{source_name_part}}bar" this will write 90 // foo${source_name_part}bar. If there are multiple templates (we were 91 // constucted with a list of more than one item) then the values will be 92 // separated by spaces. 93 // 94 // If this template is nonempty, we will first print out a space to separate 95 // it from the previous command. 96 // 97 // The names used for the Ninja variables will be the same ones used by 98 // WriteNinjaVariablesForSubstitution. You would use this to define the Ninja 99 // rule, and then define the variables to substitute for each file using 100 // WriteNinjaVariablesForSubstitution. 101 void WriteWithNinjaExpansions(std::ostream& out) const; 102 103 // Writes to the given stream the variable declarations for extracting the 104 // required parts of the given source file string. The results will be 105 // indented two spaces. 106 // 107 // This is used to set up a build statement to invoke a rule where the rule 108 // contains a representation of this file template to be expanded by Ninja 109 // (see GetWithNinjaExpansions). 110 void WriteNinjaVariablesForSubstitution( 111 std::ostream& out, 112 const std::string& source, 113 const EscapeOptions& escape_options) const; 114 115 // Returns the Ninja variable name used by the above Ninja functions to 116 // substitute for the given type. 117 static const char* GetNinjaVariableNameForType(Subrange::Type type); 118 119 // Extracts the given type of substitution from the given source. The source 120 // should be the file name relative to the output directory. 121 static std::string GetSubstitution(const std::string& source, 122 Subrange::Type type); 123 124 // Known template types, these include the "{{ }}" 125 static const char kSource[]; 126 static const char kSourceNamePart[]; 127 static const char kSourceFilePart[]; 128 129 private: 130 typedef base::StackVector<Subrange, 8> Template; 131 typedef base::StackVector<Template, 8> TemplateVector; 132 133 void ParseInput(const Value& value, Err* err); 134 135 // Parses a template string and adds it to the templates_ list. 136 void ParseOneTemplateString(const std::string& str); 137 138 TemplateVector templates_; 139 140 // The corresponding value is set to true if the given subrange type is 141 // required. This allows us to precompute these types whem applying them 142 // to a given source file. 143 bool types_required_[Subrange::NUM_TYPES]; 144 145 // Set when any of the types_required_ is true. Otherwise, everythins is a 146 // literal (a common case so we can optimize some code paths). 147 bool has_substitutions_; 148 }; 149 150 #endif // TOOLS_GN_FILE_TEMPLATE_H_ 151