• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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