blob: 05456178d8b5b7ea1d9f084ead7f117e5455bad7 [file] [log] [blame]
brettw0db91852015-05-14 23:40:201// Copyright 2015 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 "tools/gn/runtime_deps.h"
6
brettw295e07202015-07-21 23:31:117#include <map>
brettw0db91852015-05-14 23:40:208#include <set>
9#include <sstream>
10
11#include "base/command_line.h"
12#include "base/files/file_util.h"
13#include "base/strings/string_split.h"
14#include "tools/gn/build_settings.h"
15#include "tools/gn/builder.h"
16#include "tools/gn/deps_iterator.h"
17#include "tools/gn/filesystem_utils.h"
18#include "tools/gn/loader.h"
19#include "tools/gn/output_file.h"
agrieve0f8ad422016-03-31 22:00:0720#include "tools/gn/scheduler.h"
brettw0db91852015-05-14 23:40:2021#include "tools/gn/settings.h"
22#include "tools/gn/switches.h"
23#include "tools/gn/target.h"
24#include "tools/gn/trace.h"
25
26namespace {
27
28using RuntimeDepsVector = std::vector<std::pair<OutputFile, const Target*>>;
29
30// Adds the given file to the deps list if it hasn't already been listed in
31// the found_files list. Updates the list.
32void AddIfNew(const OutputFile& output_file,
33 const Target* source,
34 RuntimeDepsVector* deps,
35 std::set<OutputFile>* found_file) {
36 if (found_file->find(output_file) != found_file->end())
37 return; // Already there.
38 deps->push_back(std::make_pair(output_file, source));
39}
40
brettwe903c0f2015-06-03 22:40:1741// Automatically converts a string that looks like a source to an OutputFile.
42void AddIfNew(const std::string& str,
brettw0db91852015-05-14 23:40:2043 const Target* source,
44 RuntimeDepsVector* deps,
45 std::set<OutputFile>* found_file) {
brettwe903c0f2015-06-03 22:40:1746 OutputFile output_file(RebasePath(
47 str,
48 source->settings()->build_settings()->build_dir(),
49 source->settings()->build_settings()->root_path_utf8()));
50 AddIfNew(output_file, source, deps, found_file);
brettw0db91852015-05-14 23:40:2051}
52
brettw0db91852015-05-14 23:40:2053// To avoid duplicate traversals of targets, or duplicating output files that
54// might be listed by more than one target, the set of targets and output files
brettw295e07202015-07-21 23:31:1155// that have been found so far is passed. The "value" of the seen_targets map
56// is a boolean indicating if the seen dep was a data dep (true = data_dep).
57// data deps add more stuff, so we will want to revisit a target if it's a
58// data dependency and we've previously only seen it as a regular dep.
brettw0db91852015-05-14 23:40:2059void RecursiveCollectRuntimeDeps(const Target* target,
60 bool is_target_data_dep,
61 RuntimeDepsVector* deps,
brettw295e07202015-07-21 23:31:1162 std::map<const Target*, bool>* seen_targets,
brettw0db91852015-05-14 23:40:2063 std::set<OutputFile>* found_files) {
brettw295e07202015-07-21 23:31:1164 const auto& found_seen_target = seen_targets->find(target);
65 if (found_seen_target != seen_targets->end()) {
66 // Already visited.
67 if (found_seen_target->second || !is_target_data_dep) {
68 // Already visited as a data dep, or the current dep is not a data
69 // dep so visiting again will be a no-op.
70 return;
71 }
72 // In the else case, the previously seen target was a regular dependency
73 // and we'll now process it as a data dependency.
74 }
75 (*seen_targets)[target] = is_target_data_dep;
brettw0db91852015-05-14 23:40:2076
andybons027840d2015-10-14 18:49:3077 // Add the main output file for executables, shared libraries, and
78 // loadable modules.
brettw0db91852015-05-14 23:40:2079 if (target->output_type() == Target::EXECUTABLE ||
andybons027840d2015-10-14 18:49:3080 target->output_type() == Target::LOADABLE_MODULE ||
brettw15e0e74f2016-07-26 18:00:2481 target->output_type() == Target::SHARED_LIBRARY) {
82 for (const auto& runtime_output : target->runtime_outputs())
83 AddIfNew(runtime_output, target, deps, found_files);
84 }
brettw0db91852015-05-14 23:40:2085
86 // Add all data files.
87 for (const auto& file : target->data())
88 AddIfNew(file, target, deps, found_files);
89
90 // Actions/copy have all outputs considered when the're a data dep.
91 if (is_target_data_dep &&
92 (target->output_type() == Target::ACTION ||
93 target->output_type() == Target::ACTION_FOREACH ||
94 target->output_type() == Target::COPY_FILES)) {
95 std::vector<SourceFile> outputs;
96 target->action_values().GetOutputsAsSourceFiles(target, &outputs);
97 for (const auto& output_file : outputs)
brettwe903c0f2015-06-03 22:40:1798 AddIfNew(output_file.value(), target, deps, found_files);
brettw0db91852015-05-14 23:40:2099 }
100
rsesekbe4da4cd2016-05-31 20:10:49101 // Data dependencies.
102 for (const auto& dep_pair : target->data_deps()) {
103 RecursiveCollectRuntimeDeps(dep_pair.ptr, true,
104 deps, seen_targets, found_files);
105 }
106
rsesek903e2b82016-05-19 19:43:32107 // Do not recurse into bundle targets. A bundle's dependencies should be
108 // copied into the bundle itself for run-time access.
109 if (target->output_type() == Target::CREATE_BUNDLE) {
110 SourceDir bundle_root_dir =
111 target->bundle_data().GetBundleRootDirOutputAsDir(target->settings());
112 AddIfNew(bundle_root_dir.value(), target, deps, found_files);
113 return;
114 }
115
brettw0db91852015-05-14 23:40:20116 // Non-data dependencies (both public and private).
117 for (const auto& dep_pair : target->GetDeps(Target::DEPS_LINKED)) {
118 if (dep_pair.ptr->output_type() == Target::EXECUTABLE)
119 continue; // Skip executables that aren't data deps.
Greg Kraynov655a12bc2017-08-15 18:26:21120 if (dep_pair.ptr->output_type() == Target::SHARED_LIBRARY &&
121 (target->output_type() == Target::ACTION ||
122 target->output_type() == Target::ACTION_FOREACH)) {
123 // Skip shared libraries that action depends on,
124 // unless it were listed in data deps.
125 continue;
126 }
brettw0db91852015-05-14 23:40:20127 RecursiveCollectRuntimeDeps(dep_pair.ptr, false,
128 deps, seen_targets, found_files);
129 }
brettw0db91852015-05-14 23:40:20130}
131
agrieve0f8ad422016-03-31 22:00:07132bool CollectRuntimeDepsFromFlag(const Builder& builder,
133 RuntimeDepsVector* files_to_write,
134 Err* err) {
135 std::string deps_target_list_file =
136 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
137 switches::kRuntimeDepsListFile);
138
139 if (deps_target_list_file.empty())
140 return true;
141
142 std::string list_contents;
143 ScopedTrace load_trace(TraceItem::TRACE_FILE_LOAD, deps_target_list_file);
144 if (!base::ReadFileToString(UTF8ToFilePath(deps_target_list_file),
145 &list_contents)) {
146 *err = Err(Location(),
147 std::string("File for --") + switches::kRuntimeDepsListFile +
148 " doesn't exist.",
149 "The file given was \"" + deps_target_list_file + "\"");
150 return false;
151 }
152 load_trace.Done();
153
154 SourceDir root_dir("//");
155 Label default_toolchain_label = builder.loader()->GetDefaultToolchain();
156 for (const auto& line :
157 base::SplitString(list_contents, "\n", base::TRIM_WHITESPACE,
158 base::SPLIT_WANT_ALL)) {
159 if (line.empty())
160 continue;
161 Label label = Label::Resolve(root_dir, default_toolchain_label,
162 Value(nullptr, line), err);
163 if (err->has_error())
164 return false;
165
166 const Item* item = builder.GetItem(label);
167 const Target* target = item ? item->AsTarget() : nullptr;
168 if (!target) {
169 *err = Err(Location(), "The label \"" + label.GetUserVisibleName(true) +
170 "\" isn't a target.",
171 "When reading the line:\n " + line + "\n"
172 "from the --" + switches::kRuntimeDepsListFile + "=" +
173 deps_target_list_file);
174 return false;
175 }
176
brettw15e0e74f2016-07-26 18:00:24177 OutputFile output_file;
178 const char extension[] = ".runtime_deps";
179 if (target->output_type() == Target::SHARED_LIBRARY ||
180 target->output_type() == Target::LOADABLE_MODULE) {
181 // Force the first output for shared-library-type linker outputs since
182 // the dependency output files might not be the main output.
183 CHECK(!target->computed_outputs().empty());
184 output_file =
185 OutputFile(target->computed_outputs()[0].value() + extension);
186 } else {
187 output_file =
188 OutputFile(target->dependency_output_file().value() + extension);
189 }
agrieve0f8ad422016-03-31 22:00:07190 files_to_write->push_back(std::make_pair(output_file, target));
191 }
192 return true;
193}
194
195bool WriteRuntimeDepsFile(const OutputFile& output_file,
196 const Target* target,
197 Err* err) {
198 SourceFile output_as_source =
199 output_file.AsSourceFile(target->settings()->build_settings());
brettw0db91852015-05-14 23:40:20200 base::FilePath data_deps_file =
agrieve0f8ad422016-03-31 22:00:07201 target->settings()->build_settings()->GetFullPath(output_as_source);
brettw0db91852015-05-14 23:40:20202
203 std::stringstream contents;
204 for (const auto& pair : ComputeRuntimeDeps(target))
205 contents << pair.first.value() << std::endl;
206
agrieve0f8ad422016-03-31 22:00:07207 ScopedTrace trace(TraceItem::TRACE_FILE_WRITE, output_as_source.value());
208 return WriteFileIfChanged(data_deps_file, contents.str(), err);
brettw0db91852015-05-14 23:40:20209}
210
211} // namespace
212
213const char kRuntimeDeps_Help[] =
brettw085a9b22016-11-08 19:10:03214 R"(Runtime dependencies
215
216 Runtime dependencies of a target are exposed via the "runtime_deps" category
217 of "gn desc" (see "gn help desc") or they can be written at build generation
218 time via write_runtime_deps(), or --runtime-deps-list-file (see "gn help
219 --runtime-deps-list-file").
220
221 To a first approximation, the runtime dependencies of a target are the set of
222 "data" files, data directories, and the shared libraries from all transitive
223 dependencies. Executables, shared libraries, and loadable modules are
224 considered runtime dependencies of themselves.
225
226Executables
227
228 Executable targets and those executable targets' transitive dependencies are
229 not considered unless that executable is listed in "data_deps". Otherwise, GN
230 assumes that the executable (and everything it requires) is a build-time
231 dependency only.
232
233Actions and copies
234
235 Action and copy targets that are listed as "data_deps" will have all of their
236 outputs and data files considered as runtime dependencies. Action and copy
237 targets that are "deps" or "public_deps" will have only their data files
238 considered as runtime dependencies. These targets can list an output file in
239 both the "outputs" and "data" lists to force an output file as a runtime
240 dependency in all cases.
241
242 The different rules for deps and data_deps are to express build-time (deps)
243 vs. run-time (data_deps) outputs. If GN counted all build-time copy steps as
244 data dependencies, there would be a lot of extra stuff, and if GN counted all
245 run-time dependencies as regular deps, the build's parallelism would be
246 unnecessarily constrained.
247
248 This rule can sometimes lead to unintuitive results. For example, given the
249 three targets:
250 A --[data_deps]--> B --[deps]--> ACTION
251 GN would say that A does not have runtime deps on the result of the ACTION,
252 which is often correct. But the purpose of the B target might be to collect
253 many actions into one logic unit, and the "data"-ness of A's dependency is
254 lost. Solutions:
255
256 - List the outputs of the action in it's data section (if the results of
257 that action are always runtime files).
258 - Have B list the action in data_deps (if the outputs of the actions are
259 always runtime files).
260 - Have B list the action in both deps and data deps (if the outputs might be
261 used in both contexts and you don't care about unnecessary entries in the
262 list of files required at runtime).
263 - Split B into run-time and build-time versions with the appropriate "deps"
264 for each.
265
266Static libraries and source sets
267
268 The results of static_library or source_set targets are not considered
269 runtime dependencies since these are assumed to be intermediate targets only.
270 If you need to list a static library as a runtime dependency, you can
271 manually compute the .a/.lib file name for the current platform and list it
272 in the "data" list of a target (possibly on the static library target
273 itself).
274
275Multiple outputs
276
277 Linker tools can specify which of their outputs should be considered when
278 computing the runtime deps by setting runtime_outputs. If this is unset on
279 the tool, the default will be the first output only.
280)";
brettw0db91852015-05-14 23:40:20281
282RuntimeDepsVector ComputeRuntimeDeps(const Target* target) {
283 RuntimeDepsVector result;
brettw295e07202015-07-21 23:31:11284 std::map<const Target*, bool> seen_targets;
brettw0db91852015-05-14 23:40:20285 std::set<OutputFile> found_files;
286
287 // The initial target is not considered a data dependency so that actions's
288 // outputs (if the current target is an action) are not automatically
289 // considered data deps.
290 RecursiveCollectRuntimeDeps(target, false,
291 &result, &seen_targets, &found_files);
292 return result;
293}
294
295bool WriteRuntimeDepsFilesIfNecessary(const Builder& builder, Err* err) {
agrieve0f8ad422016-03-31 22:00:07296 RuntimeDepsVector files_to_write;
297 if (!CollectRuntimeDepsFromFlag(builder, &files_to_write, err))
brettw0db91852015-05-14 23:40:20298 return false;
agrieve0f8ad422016-03-31 22:00:07299
300 // Files scheduled by write_runtime_deps.
301 for (const Target* target : g_scheduler->GetWriteRuntimeDepsTargets()) {
302 files_to_write.push_back(
303 std::make_pair(target->write_runtime_deps_output(), target));
brettw0db91852015-05-14 23:40:20304 }
brettw0db91852015-05-14 23:40:20305
agrieve0f8ad422016-03-31 22:00:07306 for (const auto& entry : files_to_write) {
brettw0db91852015-05-14 23:40:20307 // Currently this writes all runtime deps files sequentially. We generally
308 // expect few of these. We can run this on the worker pool if it looks
309 // like it's talking a long time.
agrieve0f8ad422016-03-31 22:00:07310 if (!WriteRuntimeDepsFile(entry.first, entry.second, err))
311 return false;
brettw0db91852015-05-14 23:40:20312 }
313 return true;
314}