Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(618)

Side by Side Diff: tools/gn/runtime_deps.cc

Issue 1130183007: Add runtime dependency extraction for GN. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « tools/gn/runtime_deps.h ('k') | tools/gn/runtime_deps_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // 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
7 #include <set>
8 #include <sstream>
9
10 #include "base/command_line.h"
11 #include "base/files/file_util.h"
12 #include "base/strings/string_split.h"
13 #include "tools/gn/build_settings.h"
14 #include "tools/gn/builder.h"
15 #include "tools/gn/deps_iterator.h"
16 #include "tools/gn/filesystem_utils.h"
17 #include "tools/gn/loader.h"
18 #include "tools/gn/output_file.h"
19 #include "tools/gn/settings.h"
20 #include "tools/gn/switches.h"
21 #include "tools/gn/target.h"
22 #include "tools/gn/trace.h"
23
24 namespace {
25
26 using RuntimeDepsVector = std::vector<std::pair<OutputFile, const Target*>>;
27
28 // Adds the given file to the deps list if it hasn't already been listed in
29 // the found_files list. Updates the list.
30 void AddIfNew(const OutputFile& output_file,
31 const Target* source,
32 RuntimeDepsVector* deps,
33 std::set<OutputFile>* found_file) {
34 if (found_file->find(output_file) != found_file->end())
35 return; // Already there.
36 deps->push_back(std::make_pair(output_file, source));
37 }
38
39 // Automatically converts a SourceFile to an OutputFile.
40 void AddIfNew(const SourceFile& source_file,
41 const Target* source,
42 RuntimeDepsVector* deps,
43 std::set<OutputFile>* found_file) {
44 AddIfNew(OutputFile(source->settings()->build_settings(), source_file),
45 source, deps, found_file);
46 }
47
48 // Returns the output file that the runtime deps considers for the given
49 // targets. This is weird only for shared libraries.
50 const OutputFile& GetMainOutput(const Target* target) {
51 if (target->output_type() == Target::SHARED_LIBRARY)
52 return target->link_output_file();
53 return target->dependency_output_file();
54 }
55
56 // To avoid duplicate traversals of targets, or duplicating output files that
57 // might be listed by more than one target, the set of targets and output files
58 // that have been found so far is passed.
59 void RecursiveCollectRuntimeDeps(const Target* target,
60 bool is_target_data_dep,
61 RuntimeDepsVector* deps,
62 std::set<const Target*>* seen_targets,
63 std::set<OutputFile>* found_files) {
64 if (seen_targets->find(target) != seen_targets->end())
65 return; // Already checked.
66 seen_targets->insert(target);
67
68 // Add the main output file for executables and shared libraries.
69 if (target->output_type() == Target::EXECUTABLE ||
70 target->output_type() == Target::SHARED_LIBRARY)
71 AddIfNew(GetMainOutput(target), target, deps, found_files);
72
73 // Add all data files.
74 for (const auto& file : target->data())
75 AddIfNew(file, target, deps, found_files);
76
77 // Actions have all outputs considered when the're a data dep.
78 if (is_target_data_dep &&
79 (target->output_type() == Target::ACTION ||
80 target->output_type() == Target::ACTION_FOREACH)) {
81 std::vector<SourceFile> outputs;
82 target->action_values().GetOutputsAsSourceFiles(target, &outputs);
83 for (const auto& output_file : outputs)
84 AddIfNew(output_file, target, deps, found_files);
85 }
86
scottmg 2015/05/13 22:43:26 what about Target::COPY_FILES?
brettw 2015/05/14 16:37:26 Good question, I added COPY so it works like actio
87 // Non-data dependencies (both public and private).
88 for (const auto& dep_pair : target->GetDeps(Target::DEPS_LINKED)) {
89 if (dep_pair.ptr->output_type() == Target::EXECUTABLE)
90 continue; // Skip executables that aren't data deps.
91 RecursiveCollectRuntimeDeps(dep_pair.ptr, false,
92 deps, seen_targets, found_files);
93 }
94
95 // Data dependencies.
96 for (const auto& dep_pair : target->data_deps()) {
97 RecursiveCollectRuntimeDeps(dep_pair.ptr, true,
98 deps, seen_targets, found_files);
99 }
100 }
101
102 bool WriteRuntimeDepsFile(const Target* target) {
103 SourceFile target_output_as_source =
104 GetMainOutput(target).AsSourceFile(target->settings()->build_settings());
105 std::string data_deps_file_as_str = target_output_as_source.value();
106 data_deps_file_as_str.append(".runtime_deps");
107 base::FilePath data_deps_file =
108 target->settings()->build_settings()->GetFullPath(
109 SourceFile(SourceFile::SwapIn(), &data_deps_file_as_str));
110
111 std::stringstream contents;
112 for (const auto& pair : ComputeRuntimeDeps(target))
113 contents << pair.first.value() << std::endl;
114
115 ScopedTrace trace(TraceItem::TRACE_FILE_WRITE, data_deps_file_as_str);
116 base::CreateDirectory(data_deps_file.DirName());
117
118 std::string contents_str = contents.str();
119 return base::WriteFile(data_deps_file, contents_str.c_str(),
120 static_cast<int>(contents_str.size())) > -1;
121 }
122
123 } // namespace
124
125 const char kRuntimeDeps_Help[] =
126 "Runtime dependencies\n"
127 "\n"
128 " Runtime dependencies of a target are exposed via the \"runtime_deps\"\n"
129 " category of \"gn desc\" (see \"gn help desc\") or they can be written\n"
130 " at build generation time via \"--runtime-deps-list-file\"\n"
131 " (see \"gn help --runtime-deps-list-file\").\n"
132 "\n"
133 " To a first approximation, the runtime dependencies of a target are\n"
134 " the set of \"data\" files and the shared libraries from all transitive\n"
135 " dependencies. Executables and shared libraries are considered runtime\n"
136 " dependencies of themselves.\n"
137 "\n"
138 "Details\n"
139 "\n"
140 " Executable targets and those executable targets' transitive\n"
141 " dependencies are not considered unless that executable is listed in\n"
142 " \"data_deps\". Otherwise, GN assumes that the executable (and\n"
143 " everything it requires) is a build-time dependency only.\n"
144 "\n"
145 " Action targets that are listed as \"data_deps\" will have all of their\n"
146 " outputs and data files considered as runtime dependencies. Action\n"
147 " targets that are \"deps\" or \"public_deps\" will have only their\n"
scottmg 2015/05/13 22:43:26 I don't understand this part (and the tests for it
brettw 2015/05/14 16:33:44 The inputs are never a runtime dependency. Please
148 " data files considered as runtime dependencies. An action can list an\n"
149 " output file in both the \"outputs\" and \"data\" lists to force an\n"
150 " output file as a runtime dependency in all cases.\n"
151 "\n"
152 " The results of static_library or source_set targets are not considered\n"
153 " runtime dependencies since these are assumed to be intermediate\n"
154 " targets only. If you need to list a static library as a runtime\n"
155 " dependency, you can manually compute the .a/.lib file name for the\n"
156 " current platform and list it in the \"data\" list of a target\n"
157 " (possibly on the static library target itself).\n"
158 "\n"
159 " When a tool produces more than one output, only the first output\n"
160 " is considered. For example, a shared library target may produce a\n"
161 " .dll and a .lib file on Windows. Only the .dll file will be considered\n"
162 " a runtime dependency.\n";
163
164 RuntimeDepsVector ComputeRuntimeDeps(const Target* target) {
165 RuntimeDepsVector result;
166 std::set<const Target*> seen_targets;
167 std::set<OutputFile> found_files;
168
169 // The initial target is not considered a data dependency so that actions's
170 // outputs (if the current target is an action) are not automatically
171 // considered data deps.
172 RecursiveCollectRuntimeDeps(target, false,
173 &result, &seen_targets, &found_files);
174 return result;
175 }
176
177 bool WriteRuntimeDepsFilesIfNecessary(const Builder& builder, Err* err) {
178 std::string deps_target_list_file =
179 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
180 switches::kRuntimeDepsListFile);
181 if (deps_target_list_file.empty())
182 return true; // Nothing to do.
183
184 std::string list_contents;
185 ScopedTrace load_trace(TraceItem::TRACE_FILE_LOAD, deps_target_list_file);
186 if (!base::ReadFileToString(UTF8ToFilePath(deps_target_list_file),
187 &list_contents)) {
188 *err = Err(Location(),
189 std::string("File for --") + switches::kRuntimeDepsListFile +
190 " doesn't exist.",
191 "The file given was \"" + deps_target_list_file + "\"");
192 return false;
193 }
194 load_trace.Done();
195
196 std::vector<std::string> lines;
197 base::SplitString(list_contents, '\n', &lines);
198
199 SourceDir root_dir("//");
200 Label default_toolchain_label = builder.loader()->GetDefaultToolchain();
201 for (const auto& line : lines) {
202 if (line.empty())
203 continue;
204 Label label = Label::Resolve(root_dir, default_toolchain_label,
205 Value(nullptr, line), err);
206 if (err->has_error())
207 return false;
208
209 const Item* item = builder.GetItem(label);
210 const Target* target = nullptr;
211 if (!item || !(target = item->AsTarget())) {
212 *err = Err(Location(), "The label \"" + label.GetUserVisibleName(true) +
213 "\" isn't a target.",
214 "When reading the line:\n " + line + "\n"
215 "from the --" + switches::kRuntimeDepsListFile + "=" +
216 deps_target_list_file);
217 return false;
218 }
219
220 // Currently this writes all runtime deps files sequentially. We generally
221 // expect few of these. We can run this on the worker pool if it looks
222 // like it's talking a long time.
223 WriteRuntimeDepsFile(target);
224 }
225 return true;
226 }
OLDNEW
« no previous file with comments | « tools/gn/runtime_deps.h ('k') | tools/gn/runtime_deps_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698