Fix click-to-play positioning.
[chromium-blink-merge.git] / tools / gn / ninja_helper.cc
blob75843ee453634be3d9c97fa9f8fcf8855d27b26a
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 "base/strings/string_util.h"
9 #include "tools/gn/filesystem_utils.h"
10 #include "tools/gn/string_utils.h"
11 #include "tools/gn/target.h"
13 namespace {
15 const char kLibDirWithSlash[] = "lib/";
16 const char kObjectDirNoSlash[] = "obj";
18 } // namespace
20 NinjaHelper::NinjaHelper(const BuildSettings* build_settings)
21 : build_settings_(build_settings) {
22 build_to_src_no_last_slash_ = build_settings->build_to_source_dir_string();
23 if (!build_to_src_no_last_slash_.empty() &&
24 build_to_src_no_last_slash_[build_to_src_no_last_slash_.size() - 1] ==
25 '/')
26 build_to_src_no_last_slash_.resize(build_to_src_no_last_slash_.size() - 1);
28 build_to_src_system_no_last_slash_ = build_to_src_no_last_slash_;
31 NinjaHelper::~NinjaHelper() {
34 std::string NinjaHelper::GetTopleveOutputDir() const {
35 return kObjectDirNoSlash;
38 OutputFile NinjaHelper::GetTargetOutputDir(const Target* target) const {
39 OutputFile ret(target->settings()->toolchain_output_subdir());
40 ret.value().append(kObjectDirNoSlash);
41 AppendStringPiece(&ret.value(),
42 target->label().dir().SourceAbsoluteWithOneSlash());
43 return ret;
46 OutputFile NinjaHelper::GetNinjaFileForTarget(const Target* target) const {
47 OutputFile ret = GetTargetOutputDir(target);
48 ret.value().append(target->label().name());
49 ret.value().append(".ninja");
50 return ret;
53 OutputFile NinjaHelper::GetNinjaFileForToolchain(
54 const Settings* settings) const {
55 OutputFile ret;
56 ret.value().append(settings->toolchain_output_subdir().value());
57 ret.value().append("toolchain.ninja");
58 return ret;
61 // In Python, GypPathToUniqueOutput does the qualification. The only case where
62 // the Python version doesn't qualify the name is for target outputs, which we
63 // handle in a separate function.
64 OutputFile NinjaHelper::GetOutputFileForSource(
65 const Target* target,
66 const SourceFile& source,
67 SourceFileType type) const {
68 // Extract the filename and remove the extension (keep the dot).
69 base::StringPiece filename = FindFilename(&source.value());
70 std::string name(filename.data(), filename.size());
71 size_t extension_offset = FindExtensionOffset(name);
72 CHECK(extension_offset != std::string::npos);
73 name.resize(extension_offset);
75 // Append the new extension.
76 switch (type) {
77 case SOURCE_ASM:
78 case SOURCE_C:
79 case SOURCE_CC:
80 case SOURCE_M:
81 case SOURCE_MM:
82 case SOURCE_S:
83 name.append(target->settings()->IsWin() ? "obj" : "o");
84 break;
86 case SOURCE_RC:
87 name.append("res");
88 break;
90 // Pass .o/.obj files through unchanged.
91 case SOURCE_O: {
92 // System-absolute file names get preserved (they don't need to be
93 // rebased relative to the build dir).
94 if (source.is_system_absolute())
95 return OutputFile(source.value());
97 // Files that are already inside the build dir should not be made
98 // relative to the source tree. Doing so will insert an unnecessary
99 // "../.." into the path which won't match the corresponding target
100 // name in ninja.
101 CHECK(build_settings_->build_dir().is_source_absolute());
102 CHECK(source.is_source_absolute());
103 if (StartsWithASCII(source.value(),
104 build_settings_->build_dir().value(),
105 true)) {
106 return OutputFile(
107 source.value().substr(
108 build_settings_->build_dir().value().size()));
111 // Construct the relative location of the file from the build dir.
112 OutputFile ret(build_to_src_no_last_slash());
113 source.SourceAbsoluteWithOneSlash().AppendToString(&ret.value());
114 return ret;
117 case SOURCE_H:
118 case SOURCE_UNKNOWN:
119 NOTREACHED();
120 return OutputFile();
123 // Use the scheme <path>/<target>.<name>.<extension> so that all output
124 // names are unique to different targets.
126 // This will look like "obj" or "toolchain_name/obj".
127 OutputFile ret(target->settings()->toolchain_output_subdir());
128 ret.value().append(kObjectDirNoSlash);
130 // Find the directory, assume it starts with two slashes, and trim to one.
131 base::StringPiece dir = FindDir(&source.value());
132 CHECK(dir.size() >= 2 && dir[0] == '/' && dir[1] == '/')
133 << "Source file isn't in the source repo: " << dir;
134 AppendStringPiece(&ret.value(), dir.substr(1));
136 ret.value().append(target->label().name());
137 ret.value().append(".");
138 ret.value().append(name);
139 return ret;
142 OutputFile NinjaHelper::GetTargetOutputFile(const Target* target) const {
143 OutputFile ret;
145 // Use the output name if given, fall back to target name if not.
146 const std::string& name = target->output_name().empty() ?
147 target->label().name() : target->output_name();
149 // This is prepended to the output file name. Some platforms get "lib"
150 // prepended to library names. but be careful not to make a duplicate (e.g.
151 // some targets like "libxml" already have the "lib" in the name).
152 const char* prefix;
153 if (!target->settings()->IsWin() &&
154 (target->output_type() == Target::SHARED_LIBRARY ||
155 target->output_type() == Target::STATIC_LIBRARY) &&
156 name.compare(0, 3, "lib") != 0)
157 prefix = "lib";
158 else
159 prefix = "";
161 const char* extension;
162 if (target->output_extension().empty()) {
163 if (target->output_type() == Target::GROUP ||
164 target->output_type() == Target::SOURCE_SET ||
165 target->output_type() == Target::COPY_FILES ||
166 target->output_type() == Target::ACTION ||
167 target->output_type() == Target::ACTION_FOREACH) {
168 extension = "stamp";
169 } else {
170 extension = GetExtensionForOutputType(target->output_type(),
171 target->settings()->target_os());
173 } else {
174 extension = target->output_extension().c_str();
177 // Everything goes into the toolchain directory (which will be empty for the
178 // default toolchain, and will end in a slash otherwise).
179 ret.value().append(target->settings()->toolchain_output_subdir().value());
181 // Binaries and loadable libraries go into the toolchain root.
182 if (target->output_type() == Target::EXECUTABLE ||
183 (target->settings()->IsMac() &&
184 (target->output_type() == Target::SHARED_LIBRARY ||
185 target->output_type() == Target::STATIC_LIBRARY)) ||
186 (target->settings()->IsWin() &&
187 target->output_type() == Target::SHARED_LIBRARY)) {
188 // Generate a name like "<toolchain>/<prefix><name>.<extension>".
189 ret.value().append(prefix);
190 ret.value().append(name);
191 if (extension[0]) {
192 ret.value().push_back('.');
193 ret.value().append(extension);
195 return ret;
198 // Libraries go into the library subdirectory like
199 // "<toolchain>/lib/<prefix><name>.<extension>".
200 if (target->output_type() == Target::SHARED_LIBRARY) {
201 ret.value().append(kLibDirWithSlash);
202 ret.value().append(prefix);
203 ret.value().append(name);
204 if (extension[0]) {
205 ret.value().push_back('.');
206 ret.value().append(extension);
208 return ret;
211 // Everything else goes next to the target's .ninja file like
212 // "<toolchain>/obj/<path>/<name>.<extension>".
213 ret.value().append(kObjectDirNoSlash);
214 AppendStringPiece(&ret.value(),
215 target->label().dir().SourceAbsoluteWithOneSlash());
216 ret.value().append(prefix);
217 ret.value().append(name);
218 if (extension[0]) {
219 ret.value().push_back('.');
220 ret.value().append(extension);
222 return ret;
225 std::string NinjaHelper::GetRulePrefix(const Settings* settings) const {
226 // Don't prefix the default toolchain so it looks prettier, prefix everything
227 // else.
228 if (settings->is_default())
229 return std::string(); // Default toolchain has no prefix.
230 return settings->toolchain_label().name() + "_";
233 std::string NinjaHelper::GetRuleForSourceType(const Settings* settings,
234 SourceFileType type) const {
235 // This function may be hot since it will be called for every source file
236 // in the tree. We could cache the results to avoid making a string for
237 // every invocation.
238 std::string prefix = GetRulePrefix(settings);
240 if (type == SOURCE_C)
241 return prefix + "cc";
242 if (type == SOURCE_CC)
243 return prefix + "cxx";
244 if (type == SOURCE_M)
245 return prefix + "objc";
246 if (type == SOURCE_MM)
247 return prefix + "objcxx";
248 if (type == SOURCE_RC)
249 return prefix + "rc";
250 if (type == SOURCE_S)
251 return prefix + "cc"; // Assembly files just get compiled by CC.
253 // TODO(brettw) asm files.
255 // .obj files have no rules to make them (they're already built) so we return
256 // the enpty string for SOURCE_O.
257 return std::string();