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 *err = Err(function, "Target not found in this context.",
109 label.GetUserVisibleName(false) +
110 "\nwas not found. get_target_outputs() can only be used for "
111 "targets\n"
112 "previously defined in the current file.");
113 return Value();
114 }
115
116 // Range for GetOutputsAsSourceFiles to blame for errors.
117 LocationRange arg_range;
118 if (args[0].origin())
119 arg_range = args[0].origin()->GetRange();
120
121 std::vector<SourceFile> files;
122
123 // The build is currently running so only non-binary targets (they don't
124 // depend on the toolchain definition which may not have been loaded yet) can
125 // be queried. Pass false for build_complete so it will flag such queries as
126 // an error.
127 if (!target->GetOutputsAsSourceFiles(arg_range, false, &files, err))
128 return Value();
129
130 // Convert to Values.
131 Value ret(function, Value::LIST);
132 ret.list_value().reserve(files.size());
133 for (const auto& file : files)
134 ret.list_value().push_back(Value(function, file.value()));
135
136 return ret;
137 }
138
139 } // namespace functions
140