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 #include "base/stl_util.h"
6 #include "gn/functions.h"
7 #include "gn/parse_tree.h"
8 #include "gn/scope.h"
9 #include "gn/settings.h"
10 #include "gn/substitution_list.h"
11 #include "gn/substitution_writer.h"
12 #include "gn/target.h"
13 #include "gn/value_extractors.h"
14
15 namespace functions {
16
17 const char kProcessFileTemplate[] = "process_file_template";
18 const char kProcessFileTemplate_HelpShort[] =
19 "process_file_template: Do template expansion over a list of files.";
20 const char kProcessFileTemplate_Help[] =
21 R"(process_file_template: Do template expansion over a list of files.
22
23 process_file_template(source_list, template)
24
25 process_file_template applies a template list to a source file list,
26 returning the result of applying each template to each source. This is
27 typically used for computing output file names from input files.
28
29 In most cases, get_target_outputs() will give the same result with shorter,
30 more maintainable code. This function should only be used when that function
31 can't be used (like there's no target or the target is defined in another
32 build file).
33
34 Arguments
35
36 The source_list is a list of file names.
37
38 The template can be a string or a list. If it is a list, multiple output
39 strings are generated for each input.
40
41 The template should contain source expansions to which each name in the
42 source list is applied. See "gn help source_expansion".
43
44 Example
45
46 sources = [
47 "foo.idl",
48 "bar.idl",
49 ]
50 myoutputs = process_file_template(
51 sources,
52 [ "$target_gen_dir/{{source_name_part}}.cc",
53 "$target_gen_dir/{{source_name_part}}.h" ])
54
55 The result in this case will be:
56 [ "//out/Debug/foo.cc"
57 "//out/Debug/foo.h"
58 "//out/Debug/bar.cc"
59 "//out/Debug/bar.h" ]
60 )";
61
RunProcessFileTemplate(Scope * scope,const FunctionCallNode * function,const std::vector<Value> & args,Err * err)62 Value RunProcessFileTemplate(Scope* scope,
63 const FunctionCallNode* function,
64 const std::vector<Value>& args,
65 Err* err) {
66 if (args.size() != 2) {
67 *err = Err(function->function(), "Expected two arguments");
68 return Value();
69 }
70
71 // Source list.
72 Target::FileList input_files;
73 if (!ExtractListOfRelativeFiles(scope->settings()->build_settings(), args[0],
74 scope->GetSourceDir(), &input_files, err))
75 return Value();
76
77 std::vector<std::string> result_files;
78 SubstitutionList subst;
79
80 // Template.
81 const Value& template_arg = args[1];
82 if (template_arg.type() == Value::STRING) {
83 // Convert the string to a SubstitutionList with one pattern in it to
84 // simplify the code below.
85 std::vector<std::string> list;
86 list.push_back(template_arg.string_value());
87 if (!subst.Parse(list, template_arg.origin(), err))
88 return Value();
89 } else if (template_arg.type() == Value::LIST) {
90 if (!subst.Parse(template_arg, err))
91 return Value();
92 } else {
93 *err = Err(template_arg, "Not a string or a list.");
94 return Value();
95 }
96
97 auto& types = subst.required_types();
98 if (base::ContainsValue(types, &SubstitutionSourceTargetRelative)) {
99 *err = Err(template_arg, "Not a valid substitution type for the function.");
100 return Value();
101 }
102
103 SubstitutionWriter::ApplyListToSourcesAsString(
104 nullptr, scope->settings(), subst, input_files, &result_files);
105
106 // Convert the list of strings to the return Value.
107 Value ret(function, Value::LIST);
108 ret.list_value().reserve(result_files.size());
109 for (const auto& file : result_files)
110 ret.list_value().push_back(Value(function, file));
111
112 return ret;
113 }
114
115 } // namespace functions
116