Home | History | Annotate | Download | only in gn
      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())
     49         : 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.
     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