1 // Copyright 2014 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_SUBSTITUTION_WRITER_H_
6 #define TOOLS_GN_SUBSTITUTION_WRITER_H_
7 
8 #include <iosfwd>
9 #include <string>
10 #include <vector>
11 
12 #include "gn/substitution_type.h"
13 
14 struct EscapeOptions;
15 class OutputFile;
16 class Settings;
17 class SourceDir;
18 class SourceFile;
19 class SubstitutionList;
20 class SubstitutionPattern;
21 class Target;
22 class Tool;
23 
24 // Help text for script source expansion.
25 extern const char kSourceExpansion_Help[];
26 
27 // This class handles writing or applying substitution patterns to strings.
28 //
29 // There are several different uses:
30 //
31 //  - Source substitutions: These are used to compute action_foreach
32 //    outputs and arguments. Functions are provided to expand these in terms
33 //    of both OutputFiles (for writing Ninja files) as well as SourceFiles
34 //    (for computing lists used by code).
35 //
36 //  - Target substitutions: These are specific to the target+tool combination
37 //    and are shared between the compiler and linker ones. It includes things
38 //    like the target_gen_dir.
39 //
40 //  - Compiler substitutions: These are used to compute compiler outputs.
41 //    It includes all source substitutions (since they depend on the various
42 //    parts of the source file) as well as the target substitutions.
43 //
44 //  - Linker substitutions: These are used to compute linker outputs. It
45 //    includes the target substitutions.
46 //
47 // The compiler and linker specific substitutions do NOT include the various
48 // cflags, ldflags, libraries, etc. These are written by the ninja target
49 // writer since they depend on traversing the dependency tree.
50 //
51 // The methods which take a target as an argument can accept null target
52 // pointer if there is no target context, in which case the substitutions
53 // requiring target context will not work.
54 class SubstitutionWriter {
55  public:
56   enum OutputStyle {
57     OUTPUT_ABSOLUTE,  // Dirs will be absolute "//foo/bar".
58     OUTPUT_RELATIVE,  // Dirs will be relative to a given directory.
59   };
60 
61   // Writes the pattern to the given stream with no special handling, and with
62   // Ninja variables replacing the patterns.
63   static void WriteWithNinjaVariables(const SubstitutionPattern& pattern,
64                                       const EscapeOptions& escape_options,
65                                       std::ostream& out);
66 
67   // NOP substitutions ---------------------------------------------------------
68 
69   // Converts the given SubstitutionList to OutputFiles assuming there are
70   // no substitutions (it will assert if there are). This is used for cases
71   // like actions where the outputs are explicit, but the list is stored as
72   // a SubstitutionList.
73   static void GetListAsSourceFiles(const SubstitutionList& list,
74                                    std::vector<SourceFile>* output);
75   static void GetListAsOutputFiles(const Settings* settings,
76                                    const SubstitutionList& list,
77                                    std::vector<OutputFile>* output);
78 
79   // Source substitutions -----------------------------------------------------
80 
81   // Applies the substitution pattern to a source file, returning the result
82   // as either a string, a SourceFile or an OutputFile. If the result is
83   // expected to be a SourceFile or an OutputFile, this will CHECK if the
84   // result isn't in the correct directory. The caller should validate this
85   // first (see for example IsFileInOuputDir).
86   //
87   // The target can be null (see class comment above).
88   static SourceFile ApplyPatternToSource(const Target* target,
89                                          const Settings* settings,
90                                          const SubstitutionPattern& pattern,
91                                          const SourceFile& source);
92   static std::string ApplyPatternToSourceAsString(
93       const Target* target,
94       const Settings* settings,
95       const SubstitutionPattern& pattern,
96       const SourceFile& source);
97   static OutputFile ApplyPatternToSourceAsOutputFile(
98       const Target* target,
99       const Settings* settings,
100       const SubstitutionPattern& pattern,
101       const SourceFile& source);
102 
103   // Applies the substitution list to a source, APPENDING the result to the
104   // given output vector. It works this way so one can call multiple times to
105   // apply to multiple files and create a list. The result can either be
106   // SourceFiles or OutputFiles.
107   //
108   // The target can be null (see class comment above).
109   static void ApplyListToSource(const Target* target,
110                                 const Settings* settings,
111                                 const SubstitutionList& list,
112                                 const SourceFile& source,
113                                 std::vector<SourceFile>* output);
114   static void ApplyListToSourceAsString(const Target* target,
115                                         const Settings* settings,
116                                         const SubstitutionList& list,
117                                         const SourceFile& source,
118                                         std::vector<std::string>* output);
119   static void ApplyListToSourceAsOutputFile(const Target* target,
120                                             const Settings* settings,
121                                             const SubstitutionList& list,
122                                             const SourceFile& source,
123                                             std::vector<OutputFile>* output);
124 
125   // Like ApplyListToSource but applies the list to all sources and replaces
126   // rather than appends the output (this produces the complete output).
127   //
128   // The target can be null (see class comment above).
129   static void ApplyListToSources(const Target* target,
130                                  const Settings* settings,
131                                  const SubstitutionList& list,
132                                  const std::vector<SourceFile>& sources,
133                                  std::vector<SourceFile>* output);
134   static void ApplyListToSourcesAsString(const Target* target,
135                                          const Settings* settings,
136                                          const SubstitutionList& list,
137                                          const std::vector<SourceFile>& sources,
138                                          std::vector<std::string>* output);
139   static void ApplyListToSourcesAsOutputFile(
140       const Target* target,
141       const Settings* settings,
142       const SubstitutionList& list,
143       const std::vector<SourceFile>& sources,
144       std::vector<OutputFile>* output);
145 
146   // Given a list of source replacement types used, writes the Ninja variable
147   // definitions for the given source file to use for those replacements. The
148   // variables will be indented two spaces. Since this is for writing to
149   // Ninja files, paths will be relative to the build dir, and no definition
150   // for {{source}} will be written since that maps to Ninja's implicit $in
151   // variable.
152   //
153   // The target can be null (see class comment above).
154   static void WriteNinjaVariablesForSource(
155       const Target* target,
156       const Settings* settings,
157       const SourceFile& source,
158       const std::vector<const Substitution*>& types,
159       const EscapeOptions& escape_options,
160       std::ostream& out);
161 
162   // Extracts the given type of substitution related to a source file from the
163   // given source file. If output_style is OUTPUT_RELATIVE, relative_to
164   // indicates the directory that the relative directories should be relative
165   // to, otherwise it is ignored.
166   //
167   // The target can be null (see class comment above).
168   static std::string GetSourceSubstitution(const Target* target,
169                                            const Settings* settings,
170                                            const SourceFile& source,
171                                            const Substitution* type,
172                                            OutputStyle output_style,
173                                            const SourceDir& relative_to);
174 
175   // Target substitutions ------------------------------------------------------
176   //
177   // Handles the target substitutions that apply to both compiler and linker
178   // tools.
179   static OutputFile ApplyPatternToTargetAsOutputFile(
180       const Target* target,
181       const Tool* tool,
182       const SubstitutionPattern& pattern);
183   static void ApplyListToTargetAsOutputFile(const Target* target,
184                                             const Tool* tool,
185                                             const SubstitutionList& list,
186                                             std::vector<OutputFile>* output);
187 
188   // This function is slightly different than the other substitution getters
189   // since it can handle failure (since it is designed to be used by the
190   // compiler and linker ones which will fall through if it's not a common tool
191   // one).
192   static bool GetTargetSubstitution(const Target* target,
193                                     const Substitution* type,
194                                     std::string* result);
195   static std::string GetTargetSubstitution(const Target* target,
196                                            const Substitution* type);
197 
198   // Compiler substitutions ----------------------------------------------------
199   //
200   // A compiler substitution allows both source and tool substitutions. These
201   // are used to compute output names for compiler tools.
202 
203   static OutputFile ApplyPatternToCompilerAsOutputFile(
204       const Target* target,
205       const SourceFile& source,
206       const SubstitutionPattern& pattern);
207   static void ApplyListToCompilerAsOutputFile(const Target* target,
208                                               const SourceFile& source,
209                                               const SubstitutionList& list,
210                                               std::vector<OutputFile>* output);
211 
212   // Like GetSourceSubstitution but for strings based on the target or
213   // toolchain. This type of result will always be relative to the build
214   // directory.
215   static std::string GetCompilerSubstitution(const Target* target,
216                                              const SourceFile& source,
217                                              const Substitution* type);
218 
219   // Linker substitutions ------------------------------------------------------
220 
221   static OutputFile ApplyPatternToLinkerAsOutputFile(
222       const Target* target,
223       const Tool* tool,
224       const SubstitutionPattern& pattern);
225   static void ApplyListToLinkerAsOutputFile(const Target* target,
226                                             const Tool* tool,
227                                             const SubstitutionList& list,
228                                             std::vector<OutputFile>* output);
229 
230   // Like GetSourceSubstitution but for strings based on the target or
231   // toolchain. This type of result will always be relative to the build
232   // directory.
233   static std::string GetLinkerSubstitution(const Target* target,
234                                            const Tool* tool,
235                                            const Substitution* type);
236 };
237 
238 #endif  // TOOLS_GN_SUBSTITUTION_WRITER_H_
239