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