Revert 264226 "Reduce dependency of TiclInvalidationService on P..."
[chromium-blink-merge.git] / tools / gn / ninja_helper.cc
blobe5d1ff8efa1be39e6133cac40f74eb83adaedf2b
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_;
30 NinjaHelper::~NinjaHelper() {
33 std::string NinjaHelper::GetTopleveOutputDir() const {
34 return kObjectDirNoSlash;
37 std::string NinjaHelper::GetTargetOutputDir(const Target* target) const {
38 return kObjectDirNoSlash + target->label().dir().SourceAbsoluteWithOneSlash();
41 OutputFile NinjaHelper::GetNinjaFileForTarget(const Target* target) const {
42 OutputFile ret(target->settings()->toolchain_output_subdir());
43 ret.value().append(kObjectDirNoSlash);
44 AppendStringPiece(&ret.value(),
45 target->label().dir().SourceAbsoluteWithOneSlash());
46 ret.value().append(target->label().name());
47 ret.value().append(".ninja");
48 return ret;
51 OutputFile NinjaHelper::GetNinjaFileForToolchain(
52 const Settings* settings) const {
53 OutputFile ret;
54 ret.value().append(settings->toolchain_output_subdir().value());
55 ret.value().append("toolchain.ninja");
56 return ret;
59 // In Python, GypPathToUniqueOutput does the qualification. The only case where
60 // the Python version doesn't qualify the name is for target outputs, which we
61 // handle in a separate function.
62 OutputFile NinjaHelper::GetOutputFileForSource(
63 const Target* target,
64 const SourceFile& source,
65 SourceFileType type) const {
66 // Extract the filename and remove the extension (keep the dot).
67 base::StringPiece filename = FindFilename(&source.value());
68 std::string name(filename.data(), filename.size());
69 size_t extension_offset = FindExtensionOffset(name);
70 CHECK(extension_offset != std::string::npos);
71 name.resize(extension_offset);
73 // Append the new extension.
74 switch (type) {
75 case SOURCE_ASM:
76 case SOURCE_C:
77 case SOURCE_CC:
78 case SOURCE_M:
79 case SOURCE_MM:
80 case SOURCE_S:
81 name.append(target->settings()->IsWin() ? "obj" : "o");
82 break;
84 case SOURCE_RC:
85 name.append("res");
86 break;
88 case SOURCE_H:
89 case SOURCE_UNKNOWN:
90 NOTREACHED();
91 return OutputFile();
94 // Use the scheme <path>/<target>.<name>.<extension> so that all output
95 // names are unique to different targets.
97 // This will look like "obj" or "toolchain_name/obj".
98 OutputFile ret(target->settings()->toolchain_output_subdir());
99 ret.value().append(kObjectDirNoSlash);
101 // Find the directory, assume it starts with two slashes, and trim to one.
102 base::StringPiece dir = FindDir(&source.value());
103 CHECK(dir.size() >= 2 && dir[0] == '/' && dir[1] == '/')
104 << "Source file isn't in the source repo: " << dir;
105 AppendStringPiece(&ret.value(), dir.substr(1));
107 ret.value().append(target->label().name());
108 ret.value().append(".");
109 ret.value().append(name);
110 return ret;
113 OutputFile NinjaHelper::GetTargetOutputFile(const Target* target) const {
114 OutputFile ret;
116 // Use the output name if given, fall back to target name if not.
117 const std::string& name = target->output_name().empty() ?
118 target->label().name() : target->output_name();
120 // This is prepended to the output file name. Some platforms get "lib"
121 // prepended to library names. but be careful not to make a duplicate (e.g.
122 // some targets like "libxml" already have the "lib" in the name).
123 const char* prefix;
124 if (!target->settings()->IsWin() &&
125 (target->output_type() == Target::SHARED_LIBRARY ||
126 target->output_type() == Target::STATIC_LIBRARY) &&
127 name.compare(0, 3, "lib") != 0)
128 prefix = "lib";
129 else
130 prefix = "";
132 const char* extension;
133 if (target->output_extension().empty()) {
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::ACTION ||
138 target->output_type() == Target::ACTION_FOREACH) {
139 extension = "stamp";
140 } else {
141 extension = GetExtensionForOutputType(target->output_type(),
142 target->settings()->target_os());
144 } else {
145 extension = target->output_extension().c_str();
148 // Everything goes into the toolchain directory (which will be empty for the
149 // default toolchain, and will end in a slash otherwise).
150 ret.value().append(target->settings()->toolchain_output_subdir().value());
152 // Binaries and loadable libraries go into the toolchain root.
153 if (target->output_type() == Target::EXECUTABLE ||
154 (target->settings()->IsMac() &&
155 (target->output_type() == Target::SHARED_LIBRARY ||
156 target->output_type() == Target::STATIC_LIBRARY)) ||
157 (target->settings()->IsWin() &&
158 target->output_type() == Target::SHARED_LIBRARY)) {
159 // Generate a name like "<toolchain>/<prefix><name>.<extension>".
160 ret.value().append(prefix);
161 ret.value().append(name);
162 if (extension[0]) {
163 ret.value().push_back('.');
164 ret.value().append(extension);
166 return ret;
169 // Libraries go into the library subdirectory like
170 // "<toolchain>/lib/<prefix><name>.<extension>".
171 if (target->output_type() == Target::SHARED_LIBRARY) {
172 ret.value().append(kLibDirWithSlash);
173 ret.value().append(prefix);
174 ret.value().append(name);
175 if (extension[0]) {
176 ret.value().push_back('.');
177 ret.value().append(extension);
179 return ret;
182 // Everything else goes next to the target's .ninja file like
183 // "<toolchain>/obj/<path>/<name>.<extension>".
184 ret.value().append(kObjectDirNoSlash);
185 AppendStringPiece(&ret.value(),
186 target->label().dir().SourceAbsoluteWithOneSlash());
187 ret.value().append(prefix);
188 ret.value().append(name);
189 if (extension[0]) {
190 ret.value().push_back('.');
191 ret.value().append(extension);
193 return ret;
196 std::string NinjaHelper::GetRulePrefix(const Settings* settings) const {
197 // Don't prefix the default toolchain so it looks prettier, prefix everything
198 // else.
199 if (settings->is_default())
200 return std::string(); // Default toolchain has no prefix.
201 return settings->toolchain_label().name() + "_";
204 std::string NinjaHelper::GetRuleForSourceType(const Settings* settings,
205 SourceFileType type) const {
206 // This function may be hot since it will be called for every source file
207 // in the tree. We could cache the results to avoid making a string for
208 // every invocation.
209 std::string prefix = GetRulePrefix(settings);
211 if (type == SOURCE_C)
212 return prefix + "cc";
213 if (type == SOURCE_CC)
214 return prefix + "cxx";
215 if (type == SOURCE_M)
216 return prefix + "objc";
217 if (type == SOURCE_MM)
218 return prefix + "objcxx";
219 if (type == SOURCE_RC)
220 return prefix + "rc";
221 if (type == SOURCE_S)
222 return prefix + "cc"; // Assembly files just get compiled by CC.
224 // TODO(brettw) asm files.
226 return std::string();