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

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

Issue 2156173003: Re-land r406064 "[GN] Add JSON project writer". (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: clear dependency Created 4 years, 5 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/json_project_writer.h ('k') | tools/gn/target.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 (c) 2016 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/json_project_writer.h"
6
7 #include <iostream>
8
9 #include "base/command_line.h"
10 #include "base/json/json_writer.h"
11 #include "base/memory/ptr_util.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "tools/gn/builder.h"
14 #include "tools/gn/commands.h"
15 #include "tools/gn/deps_iterator.h"
16 #include "tools/gn/desc_builder.h"
17 #include "tools/gn/exec_process.h"
18 #include "tools/gn/filesystem_utils.h"
19 #include "tools/gn/settings.h"
20
21 // Structure of JSON output file
22 // {
23 // "build_settings" = {
24 // "root_path" : "absolute path of project root",
25 // "build_dir" : "build directory (project relative)",
26 // "default_toolchain" : "name of default toolchain"
27 // }
28 // "targets" = {
29 // "target x name" : { target x properties },
30 // "target y name" : { target y properties },
31 // ...
32 // }
33 // }
34 // See desc_builder.cc for overview of target properties
35
36 namespace {
37
38 void AddTargetDependencies(const Target* target,
39 std::set<const Target*>* deps) {
40 for (const auto& pair : target->GetDeps(Target::DEPS_LINKED)) {
41 if (deps->find(pair.ptr) == deps->end()) {
42 deps->insert(pair.ptr);
43 AddTargetDependencies(pair.ptr, deps);
44 }
45 }
46 }
47
48 // Filters targets according to filter string; Will also recursively
49 // add dependent targets.
50 bool FilterTargets(const BuildSettings* build_settings,
51 std::vector<const Target*>& all_targets,
52 std::vector<const Target*>* targets,
53 const std::string& dir_filter_string,
54 Err* err) {
55 if (dir_filter_string.empty()) {
56 *targets = all_targets;
57 } else {
58 targets->reserve(all_targets.size());
59 std::vector<LabelPattern> filters;
60 if (!commands::FilterPatternsFromString(build_settings, dir_filter_string,
61 &filters, err)) {
62 return false;
63 }
64 commands::FilterTargetsByPatterns(all_targets, filters, targets);
65
66 std::set<const Target*> target_set(targets->begin(), targets->end());
67 for (const auto* target : *targets)
68 AddTargetDependencies(target, &target_set);
69
70 targets->clear();
71 targets->insert(targets->end(), target_set.begin(), target_set.end());
72 }
73
74 // Sort the list of targets per-label to get a consistent ordering of them
75 // in the generated project (and thus stability of the file generated).
76 std::sort(targets->begin(), targets->end(),
77 [](const Target* a, const Target* b) {
78 return a->label().name() < b->label().name();
79 });
80
81 return true;
82 }
83
84 std::string RenderJSON(const BuildSettings* build_settings,
85 const Builder* builder,
86 std::vector<const Target*>& all_targets) {
87 Label default_toolchain_label;
88
89 auto targets = base::WrapUnique(new base::DictionaryValue());
90 for (const auto* target : all_targets) {
91 if (default_toolchain_label.is_null())
92 default_toolchain_label = target->settings()->default_toolchain_label();
93 auto description =
94 DescBuilder::DescriptionForTarget(target, "", false, false, false);
95 // Outputs need to be asked for separately.
96 auto outputs = DescBuilder::DescriptionForTarget(target, "source_outputs",
97 false, false, false);
98 base::DictionaryValue* outputs_value = nullptr;
99 if (outputs->GetDictionary("source_outputs", &outputs_value) &&
100 !outputs_value->empty()) {
101 description->MergeDictionary(outputs.get());
102 }
103 targets->Set(target->label().GetUserVisibleName(default_toolchain_label),
104 std::move(description));
105 }
106
107 auto settings = base::WrapUnique(new base::DictionaryValue());
108 settings->SetString("root_path", build_settings->root_path_utf8());
109 settings->SetString("build_dir", build_settings->build_dir().value());
110 settings->SetString("default_toolchain",
111 default_toolchain_label.GetUserVisibleName(false));
112
113 auto output = base::WrapUnique(new base::DictionaryValue());
114 output->Set("targets", std::move(targets));
115 output->Set("build_settings", std::move(settings));
116
117 std::string s;
118 base::JSONWriter::WriteWithOptions(
119 *output.get(), base::JSONWriter::OPTIONS_PRETTY_PRINT, &s);
120 return s;
121 }
122
123 bool InvokePython(const BuildSettings* build_settings,
124 const base::FilePath& python_script_path,
125 const std::string& python_script_extra_args,
126 const base::FilePath& output_path,
127 bool quiet,
128 Err* err) {
129 const base::FilePath& python_path = build_settings->python_path();
130 base::CommandLine cmdline(python_path);
131 cmdline.AppendArg("--");
132 cmdline.AppendArgPath(python_script_path);
133 cmdline.AppendArgPath(output_path);
134 if (!python_script_extra_args.empty()) {
135 cmdline.AppendArg(python_script_extra_args);
136 }
137 base::FilePath startup_dir =
138 build_settings->GetFullPath(build_settings->build_dir());
139
140 std::string output;
141 std::string stderr_output;
142
143 int exit_code = 0;
144 if (!internal::ExecProcess(cmdline, startup_dir, &output, &stderr_output,
145 &exit_code)) {
146 *err =
147 Err(Location(), "Could not execute python.",
148 "I was trying to execute \"" + FilePathToUTF8(python_path) + "\".");
149 return false;
150 }
151
152 if (!quiet) {
153 std::cout << output;
154 std::cerr << stderr_output;
155 }
156
157 if (exit_code != 0) {
158 *err = Err(Location(), "Python has quit with exit code " +
159 base::IntToString(exit_code) + ".");
160 return false;
161 }
162
163 return true;
164 }
165
166 } // namespace
167
168 bool JSONProjectWriter::RunAndWriteFiles(
169 const BuildSettings* build_settings,
170 const Builder* builder,
171 const std::string& file_name,
172 const std::string& exec_script,
173 const std::string& exec_script_extra_args,
174 const std::string& dir_filter_string,
175 bool quiet,
176 Err* err) {
177 SourceFile output_file = build_settings->build_dir().ResolveRelativeFile(
178 Value(nullptr, file_name), err);
179 if (output_file.is_null()) {
180 return false;
181 }
182
183 base::FilePath output_path = build_settings->GetFullPath(output_file);
184
185 std::vector<const Target*> all_targets = builder->GetAllResolvedTargets();
186 std::vector<const Target*> targets;
187 if (!FilterTargets(build_settings, all_targets, &targets, dir_filter_string,
188 err)) {
189 return false;
190 }
191
192 std::string json = RenderJSON(build_settings, builder, targets);
193 if (!ContentsEqual(output_path, json)) {
194 if (!WriteFileIfChanged(output_path, json, err)) {
195 return false;
196 }
197
198 if (!exec_script.empty()) {
199 SourceFile script_file;
200 if (exec_script[0] != '/') {
201 // Relative path, assume the base is in build_dir.
202 script_file = build_settings->build_dir().ResolveRelativeFile(
203 Value(nullptr, exec_script), err);
204 if (script_file.is_null()) {
205 return false;
206 }
207 } else {
208 script_file = SourceFile(exec_script);
209 }
210 base::FilePath script_path = build_settings->GetFullPath(script_file);
211 return InvokePython(build_settings, script_path, exec_script_extra_args,
212 output_path, quiet, err);
213 }
214 }
215
216 return true;
217 }
OLDNEW
« no previous file with comments | « tools/gn/json_project_writer.h ('k') | tools/gn/target.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698