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 #include "gn/build_settings.h"
6 #include "gn/functions.h"
7 #include "gn/parse_tree.h"
8 #include "gn/settings.h"
9 #include "gn/substitution_writer.h"
10 #include "gn/target.h"
11 #include "gn/value.h"
12
13 namespace functions {
14
15 const char kGetTargetOutputs[] = "get_target_outputs";
16 const char kGetTargetOutputs_HelpShort[] =
17 "get_target_outputs: [file list] Get the list of outputs from a target.";
18 const char kGetTargetOutputs_Help[] =
19 R"(get_target_outputs: [file list] Get the list of outputs from a target.
20
21 get_target_outputs(target_label)
22
23 Returns a list of output files for the named target. The named target must
24 have been previously defined in the current file before this function is
25 called (it can't reference targets in other files because there isn't a
26 defined execution order, and it obviously can't reference targets that are
27 defined after the function call).
28
29 Only copy, generated_file, and action targets are supported. The outputs from
30 binary targets will depend on the toolchain definition which won't
31 necessarily have been loaded by the time a given line of code has run, and
32 source sets and groups have no useful output file.
33
34 Return value
35
36 The names in the resulting list will be absolute file paths (normally like
37 "//out/Debug/bar.exe", depending on the build directory).
38
39 action, copy, and generated_file targets: this will just return the files
40 specified in the "outputs" variable of the target.
41
42 action_foreach targets: this will return the result of applying the output
43 template to the sources (see "gn help source_expansion"). This will be the
44 same result (though with guaranteed absolute file paths), as
45 process_file_template will return for those inputs (see "gn help
46 process_file_template").
47
48 source sets and groups: this will return a list containing the path of the
49 "stamp" file that Ninja will produce once all outputs are generated. This
50 probably isn't very useful.
51
52 Example
53
54 # Say this action generates a bunch of C source files.
55 action_foreach("my_action") {
56 sources = [ ... ]
57 outputs = [ ... ]
58 }
59
60 # Compile the resulting source files into a source set.
61 source_set("my_lib") {
62 sources = get_target_outputs(":my_action")
63 }
64 )";
65
RunGetTargetOutputs(Scope * scope,const FunctionCallNode * function,const std::vector<Value> & args,Err * err)66 Value RunGetTargetOutputs(Scope* scope,
67 const FunctionCallNode* function,
68 const std::vector<Value>& args,
69 Err* err) {
70 if (args.size() != 1) {
71 *err = Err(function, "Expected one argument.");
72 return Value();
73 }
74
75 // Resolve the requested label.
76 Label label =
77 Label::Resolve(scope->GetSourceDir(),
78 scope->settings()->build_settings()->root_path_utf8(),
79 ToolchainLabelForScope(scope), args[0], err);
80 if (label.is_null())
81 return Value();
82
83 // Find the referenced target. The targets previously encountered in this
84 // scope will have been stashed in the item collector (they'll be dispatched
85 // when this file is done running) so we can look through them.
86 const Target* target = nullptr;
87 Scope::ItemVector* collector = scope->GetItemCollector();
88 if (!collector) {
89 *err = Err(function, "No targets defined in this context.");
90 return Value();
91 }
92 for (const auto& item : *collector) {
93 if (item->label() != label)
94 continue;
95
96 const Target* as_target = item->AsTarget();
97 if (!as_target) {
98 *err = Err(function, "Label does not refer to a target.",
99 label.GetUserVisibleName(false) + "\nrefers to a " +
100 item->GetItemTypeName());
101 return Value();
102 }
103 target = as_target;
104 break;
105 }
106
107 if (!target) {
108 bool with_toolchain = !scope->settings()->is_default();
109 *err = Err(function, "Target not found in this context.",
110 label.GetUserVisibleName(with_toolchain) +
111 "\nwas not found. get_target_outputs() can only be used for "
112 "targets\n"
113 "previously defined in the current file.");
114 return Value();
115 }
116
117 // Range for GetOutputsAsSourceFiles to blame for errors.
118 LocationRange arg_range;
119 if (args[0].origin())
120 arg_range = args[0].origin()->GetRange();
121
122 std::vector<SourceFile> files;
123
124 // The build is currently running so only non-binary targets (they don't
125 // depend on the toolchain definition which may not have been loaded yet) can
126 // be queried. Pass false for build_complete so it will flag such queries as
127 // an error.
128 if (!target->GetOutputsAsSourceFiles(arg_range, false, &files, err))
129 return Value();
130
131 // Convert to Values.
132 Value ret(function, Value::LIST);
133 ret.list_value().reserve(files.size());
134 for (const auto& file : files)
135 ret.list_value().push_back(Value(function, file.value()));
136
137 return ret;
138 }
139
140 } // namespace functions
141