// 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. #ifndef TOOLS_GN_FILE_TEMPLATE_H_ #define TOOLS_GN_FILE_TEMPLATE_H_ #include <iosfwd> #include "base/basictypes.h" #include "base/containers/stack_container.h" #include "tools/gn/err.h" #include "tools/gn/value.h" struct EscapeOptions; class ParseNode; class Target; extern const char kSourceExpansion_Help[]; // A FileTemplate object implements source expansion for a given "template" // (either outputs or args, depending on the target type). // // There are two ways you can use this. You can make a template and then // apply a source to it to get a list of outputs manually. Or you can do the // actual substitution in Ninja, writing the arguments in a rule and using // variables in build statements to invoke the rule with the right // substitutions. class FileTemplate { public: struct Subrange { enum Type { LITERAL = 0, // {{source}} -> expands to be the source file name relative to the build // root dir. SOURCE, // {{source_name_part}} -> file name without extension or directory. // Maps "foo/bar.txt" to "bar". NAME_PART, // {{source_file_part}} -> file name including extension but no directory. // Maps "foo/bar.txt" to "bar.txt". FILE_PART, NUM_TYPES // Must be last }; Subrange(Type t, const std::string& l = std::string()) : type(t), literal(l) { } Type type; // When type_ == LITERAL, this specifies the literal. std::string literal; }; // Constructs a template from the given value. On error, the err will be // set. In this case you should not use this object. FileTemplate(const Value& t, Err* err); FileTemplate(const std::vector<std::string>& t); ~FileTemplate(); // Returns an output template representing the given target's script // outputs. static FileTemplate GetForTargetOutputs(const Target* target); // Returns true if the given substitution type is used by this template. bool IsTypeUsed(Subrange::Type type) const; // Returns true if there are any substitutions. bool has_substitutions() const { return has_substitutions_; } // Applies this template to the given list of sources, appending all // results to the given dest list. The sources must be a list for the // one that takes a value as an input, otherwise the given error will be set. void Apply(const Value& sources, const ParseNode* origin, std::vector<Value>* dest, Err* err) const; void ApplyString(const std::string& input, std::vector<std::string>* output) const; // Writes a string representing the template with Ninja variables for the // substitutions, and the literals escaped for Ninja consumption. // // For example, if the input is "foo{{source_name_part}}bar" this will write // foo${source_name_part}bar. If there are multiple templates (we were // constucted with a list of more than one item) then the values will be // separated by spaces. // // If this template is nonempty, we will first print out a space to separate // it from the previous command. // // The names used for the Ninja variables will be the same ones used by // WriteNinjaVariablesForSubstitution. You would use this to define the Ninja // rule, and then define the variables to substitute for each file using // WriteNinjaVariablesForSubstitution. void WriteWithNinjaExpansions(std::ostream& out) const; // Writes to the given stream the variable declarations for extracting the // required parts of the given source file string. The results will be // indented two spaces. // // This is used to set up a build statement to invoke a rule where the rule // contains a representation of this file template to be expanded by Ninja // (see GetWithNinjaExpansions). void WriteNinjaVariablesForSubstitution( std::ostream& out, const std::string& source, const EscapeOptions& escape_options) const; // Returns the Ninja variable name used by the above Ninja functions to // substitute for the given type. static const char* GetNinjaVariableNameForType(Subrange::Type type); // Extracts the given type of substitution from the given source. The source // should be the file name relative to the output directory. static std::string GetSubstitution(const std::string& source, Subrange::Type type); // Known template types, these include the "{{ }}" static const char kSource[]; static const char kSourceNamePart[]; static const char kSourceFilePart[]; private: typedef base::StackVector<Subrange, 8> Template; typedef base::StackVector<Template, 8> TemplateVector; void ParseInput(const Value& value, Err* err); // Parses a template string and adds it to the templates_ list. void ParseOneTemplateString(const std::string& str); TemplateVector templates_; // The corresponding value is set to true if the given subrange type is // required. This allows us to precompute these types whem applying them // to a given source file. bool types_required_[Subrange::NUM_TYPES]; // Set when any of the types_required_ is true. Otherwise, everythins is a // literal (a common case so we can optimize some code paths). bool has_substitutions_; }; #endif // TOOLS_GN_FILE_TEMPLATE_H_