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