Add UMA stats for ExtensionCache
[chromium-blink-merge.git] / tools / gn / ninja_helper.cc
blobe872c2411248d8b51808450a57348483d2aa2d06
1 // Copyright (c) 2013 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.
5 #include "tools/gn/ninja_helper.h"
7 #include "base/logging.h"
8 #include "tools/gn/filesystem_utils.h"
9 #include "tools/gn/string_utils.h"
10 #include "tools/gn/target.h"
12 namespace {
14 const char kLibDirWithSlash[] = "lib/";
15 const char kObjectDirNoSlash[] = "obj";
17 } // namespace
19 NinjaHelper::NinjaHelper(const BuildSettings* build_settings)
20 : build_settings_(build_settings) {
21 build_to_src_no_last_slash_ = build_settings->build_to_source_dir_string();
22 if (!build_to_src_no_last_slash_.empty() &&
23 build_to_src_no_last_slash_[build_to_src_no_last_slash_.size() - 1] ==
24 '/')
25 build_to_src_no_last_slash_.resize(build_to_src_no_last_slash_.size() - 1);
27 build_to_src_system_no_last_slash_ = build_to_src_no_last_slash_;
28 ConvertPathToSystem(&build_to_src_system_no_last_slash_);
31 NinjaHelper::~NinjaHelper() {
34 std::string NinjaHelper::GetTopleveOutputDir() const {
35 return kObjectDirNoSlash;
38 std::string NinjaHelper::GetTargetOutputDir(const Target* target) const {
39 return kObjectDirNoSlash + target->label().dir().SourceAbsoluteWithOneSlash();
42 OutputFile NinjaHelper::GetNinjaFileForTarget(const Target* target) const {
43 OutputFile ret(target->settings()->toolchain_output_subdir());
44 ret.value().append(kObjectDirNoSlash);
45 AppendStringPiece(&ret.value(),
46 target->label().dir().SourceAbsoluteWithOneSlash());
47 ret.value().append(target->label().name());
48 ret.value().append(".ninja");
49 return ret;
52 OutputFile NinjaHelper::GetNinjaFileForToolchain(
53 const Settings* settings) const {
54 OutputFile ret;
55 ret.value().append(settings->toolchain_output_subdir().value());
56 ret.value().append("toolchain.ninja");
57 return ret;
60 // In Python, GypPathToUniqueOutput does the qualification. The only case where
61 // the Python version doesn't qualify the name is for target outputs, which we
62 // handle in a separate function.
63 OutputFile NinjaHelper::GetOutputFileForSource(
64 const Target* target,
65 const SourceFile& source,
66 SourceFileType type) const {
67 // Extract the filename and remove the extension (keep the dot).
68 base::StringPiece filename = FindFilename(&source.value());
69 std::string name(filename.data(), filename.size());
70 size_t extension_offset = FindExtensionOffset(name);
71 CHECK(extension_offset != std::string::npos);
72 name.resize(extension_offset);
74 // Append the new extension.
75 switch (type) {
76 case SOURCE_ASM:
77 case SOURCE_C:
78 case SOURCE_CC:
79 case SOURCE_M:
80 case SOURCE_MM:
81 case SOURCE_S:
82 name.append(target->settings()->IsWin() ? "obj" : "o");
83 break;
85 case SOURCE_RC:
86 name.append("res");
87 break;
89 case SOURCE_H:
90 case SOURCE_UNKNOWN:
91 NOTREACHED();
92 return OutputFile();
95 // Use the scheme <path>/<target>.<name>.<extension> so that all output
96 // names are unique to different targets.
98 // This will look like "obj" or "toolchain_name/obj".
99 OutputFile ret(target->settings()->toolchain_output_subdir());
100 ret.value().append(kObjectDirNoSlash);
102 // Find the directory, assume it starts with two slashes, and trim to one.
103 base::StringPiece dir = FindDir(&source.value());
104 CHECK(dir.size() >= 2 && dir[0] == '/' && dir[1] == '/')
105 << "Source file isn't in the source repo: " << dir;
106 AppendStringPiece(&ret.value(), dir.substr(1));
108 ret.value().append(target->label().name());
109 ret.value().append(".");
110 ret.value().append(name);
111 return ret;
114 OutputFile NinjaHelper::GetTargetOutputFile(const Target* target) const {
115 OutputFile ret;
117 // Use the output name if given, fall back to target name if not.
118 const std::string& name = target->output_name().empty() ?
119 target->label().name() : target->output_name();
121 // This is prepended to the output file name. Some platforms get "lib"
122 // prepended to library names. but be careful not to make a duplicate (e.g.
123 // some targets like "libxml" already have the "lib" in the name).
124 const char* prefix;
125 if (!target->settings()->IsWin() &&
126 (target->output_type() == Target::SHARED_LIBRARY ||
127 target->output_type() == Target::STATIC_LIBRARY) &&
128 name.compare(0, 3, "lib") != 0)
129 prefix = "lib";
130 else
131 prefix = "";
133 const char* extension;
134 if (target->output_type() == Target::GROUP ||
135 target->output_type() == Target::SOURCE_SET ||
136 target->output_type() == Target::COPY_FILES ||
137 target->output_type() == Target::CUSTOM) {
138 extension = "stamp";
139 } else {
140 extension = GetExtensionForOutputType(target->output_type(),
141 target->settings()->target_os());
144 // Everything goes into the toolchain directory (which will be empty for the
145 // default toolchain, and will end in a slash otherwise).
146 ret.value().append(target->settings()->toolchain_output_subdir().value());
148 // Binaries and loadable libraries go into the toolchain root.
149 if (target->output_type() == Target::EXECUTABLE ||
150 (target->settings()->IsMac() &&
151 (target->output_type() == Target::SHARED_LIBRARY ||
152 target->output_type() == Target::STATIC_LIBRARY)) ||
153 (target->settings()->IsWin() &&
154 target->output_type() == Target::SHARED_LIBRARY)) {
155 // Generate a name like "<toolchain>/<prefix><name>.<extension>".
156 ret.value().append(prefix);
157 ret.value().append(name);
158 if (extension[0]) {
159 ret.value().push_back('.');
160 ret.value().append(extension);
162 return ret;
165 // Libraries go into the library subdirectory like
166 // "<toolchain>/lib/<prefix><name>.<extension>".
167 if (target->output_type() == Target::SHARED_LIBRARY) {
168 ret.value().append(kLibDirWithSlash);
169 ret.value().append(prefix);
170 ret.value().append(name);
171 if (extension[0]) {
172 ret.value().push_back('.');
173 ret.value().append(extension);
175 return ret;
178 // Everything else goes next to the target's .ninja file like
179 // "<toolchain>/obj/<path>/<name>.<extension>".
180 ret.value().append(kObjectDirNoSlash);
181 AppendStringPiece(&ret.value(),
182 target->label().dir().SourceAbsoluteWithOneSlash());
183 ret.value().append(prefix);
184 ret.value().append(name);
185 if (extension[0]) {
186 ret.value().push_back('.');
187 ret.value().append(extension);
189 return ret;
192 std::string NinjaHelper::GetRulePrefix(const Settings* settings) const {
193 // Don't prefix the default toolchain so it looks prettier, prefix everything
194 // else.
195 if (settings->is_default())
196 return std::string(); // Default toolchain has no prefix.
197 return settings->toolchain_label().name() + "_";
200 std::string NinjaHelper::GetRuleForSourceType(const Settings* settings,
201 SourceFileType type) const {
202 // This function may be hot since it will be called for every source file
203 // in the tree. We could cache the results to avoid making a string for
204 // every invocation.
205 std::string prefix = GetRulePrefix(settings);
207 if (type == SOURCE_C)
208 return prefix + "cc";
209 if (type == SOURCE_CC)
210 return prefix + "cxx";
212 // TODO(brettw) asm files.
214 if (settings->IsMac()) {
215 if (type == SOURCE_M)
216 return prefix + "objc";
217 if (type == SOURCE_MM)
218 return prefix + "objcxx";
221 if (settings->IsWin()) {
222 if (type == SOURCE_RC)
223 return prefix + "rc";
224 } else {
225 if (type == SOURCE_S)
226 return prefix + "cc"; // Assembly files just get compiled by CC.
229 return std::string();