OLD | NEW |
---|---|
(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 } | |
OLD | NEW |