Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / tools / gn / ninja_helper.cc
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.
4
5 #include "tools/gn/ninja_helper.h"
6
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"
12
13 namespace {
14
15 const char kObjectDirNoSlash[] = "obj";
16
17 }  // namespace
18
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);
26
27   build_to_src_system_no_last_slash_ = build_to_src_no_last_slash_;
28 }
29
30 NinjaHelper::~NinjaHelper() {
31 }
32
33 std::string NinjaHelper::GetTopleveOutputDir() const {
34   return kObjectDirNoSlash;
35 }
36
37 OutputFile NinjaHelper::GetTargetOutputDir(const Target* target) const {
38   OutputFile ret(target->settings()->toolchain_output_subdir());
39   ret.value().append(kObjectDirNoSlash);
40   AppendStringPiece(&ret.value(),
41                     target->label().dir().SourceAbsoluteWithOneSlash());
42   return ret;
43 }
44
45 OutputFile NinjaHelper::GetNinjaFileForTarget(const Target* target) const {
46   OutputFile ret = GetTargetOutputDir(target);
47   ret.value().append(target->label().name());
48   ret.value().append(".ninja");
49   return ret;
50 }
51
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;
58 }
59
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);
73
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;
84
85     case SOURCE_RC:
86       name.append("res");
87       break;
88
89     // Pass .o/.obj files through unchanged.
90     case SOURCE_O: {
91       // System-absolute file names get preserved (they don't need to be
92       // rebased relative to the build dir).
93       if (source.is_system_absolute())
94         return OutputFile(source.value());
95
96       // Files that are already inside the build dir should not be made
97       // relative to the source tree. Doing so will insert an unnecessary
98       // "../.." into the path which won't match the corresponding target
99       // name in ninja.
100       CHECK(build_settings_->build_dir().is_source_absolute());
101       CHECK(source.is_source_absolute());
102       if (StartsWithASCII(source.value(),
103                           build_settings_->build_dir().value(),
104                           true)) {
105         return OutputFile(
106             source.value().substr(
107                 build_settings_->build_dir().value().size()));
108       }
109
110       // Construct the relative location of the file from the build dir.
111       OutputFile ret(build_to_src_no_last_slash());
112       source.SourceAbsoluteWithOneSlash().AppendToString(&ret.value());
113       return ret;
114     }
115
116     case SOURCE_H:
117     case SOURCE_UNKNOWN:
118       NOTREACHED();
119       return OutputFile();
120   }
121
122   // Use the scheme <path>/<target>.<name>.<extension> so that all output
123   // names are unique to different targets.
124
125   // This will look like "obj" or "toolchain_name/obj".
126   OutputFile ret(target->settings()->toolchain_output_subdir());
127   ret.value().append(kObjectDirNoSlash);
128
129   // Find the directory, assume it starts with two slashes, and trim to one.
130   base::StringPiece dir = FindDir(&source.value());
131   CHECK(dir.size() >= 2 && dir[0] == '/' && dir[1] == '/')
132       << "Source file isn't in the source repo: " << dir;
133   AppendStringPiece(&ret.value(), dir.substr(1));
134
135   ret.value().append(target->label().name());
136   ret.value().append(".");
137   ret.value().append(name);
138   return ret;
139 }
140
141 OutputFile NinjaHelper::GetTargetOutputFile(const Target* target) const {
142   OutputFile ret;
143
144   // Use the output name if given, fall back to target name if not.
145   const std::string& name = target->output_name().empty() ?
146       target->label().name() : target->output_name();
147
148   // This is prepended to the output file name. Some platforms get "lib"
149   // prepended to library names. but be careful not to make a duplicate (e.g.
150   // some targets like "libxml" already have the "lib" in the name).
151   const char* prefix;
152   if (!target->settings()->IsWin() &&
153       (target->output_type() == Target::SHARED_LIBRARY ||
154        target->output_type() == Target::STATIC_LIBRARY) &&
155       name.compare(0, 3, "lib") != 0)
156     prefix = "lib";
157   else
158     prefix = "";
159
160   const char* extension;
161   if (target->output_extension().empty()) {
162     if (target->output_type() == Target::GROUP ||
163         target->output_type() == Target::SOURCE_SET ||
164         target->output_type() == Target::COPY_FILES ||
165         target->output_type() == Target::ACTION ||
166         target->output_type() == Target::ACTION_FOREACH) {
167       extension = "stamp";
168     } else {
169       extension = GetExtensionForOutputType(target->output_type(),
170                                             target->settings()->target_os());
171     }
172   } else {
173     extension = target->output_extension().c_str();
174   }
175
176   // Everything goes into the toolchain directory (which will be empty for the
177   // default toolchain, and will end in a slash otherwise).
178   ret.value().append(target->settings()->toolchain_output_subdir().value());
179
180   // Binaries and shared libraries go into the toolchain root.
181   if (target->output_type() == Target::EXECUTABLE ||
182       target->output_type() == Target::SHARED_LIBRARY) {
183     // Generate a name like "<toolchain>/<prefix><name>.<extension>".
184     ret.value().append(prefix);
185     ret.value().append(name);
186     if (extension[0]) {
187       ret.value().push_back('.');
188       ret.value().append(extension);
189     }
190     return ret;
191   }
192
193   // Everything else goes next to the target's .ninja file like
194   // "<toolchain>/obj/<path>/<name>.<extension>".
195   ret.value().append(kObjectDirNoSlash);
196   AppendStringPiece(&ret.value(),
197                     target->label().dir().SourceAbsoluteWithOneSlash());
198   ret.value().append(prefix);
199   ret.value().append(name);
200   if (extension[0]) {
201     ret.value().push_back('.');
202     ret.value().append(extension);
203   }
204   return ret;
205 }
206
207 std::string NinjaHelper::GetRulePrefix(const Settings* settings) const {
208   // Don't prefix the default toolchain so it looks prettier, prefix everything
209   // else.
210   if (settings->is_default())
211     return std::string();  // Default toolchain has no prefix.
212   return settings->toolchain_label().name() + "_";
213 }
214
215 std::string NinjaHelper::GetRuleForSourceType(const Settings* settings,
216                                               SourceFileType type) const {
217   // This function may be hot since it will be called for every source file
218   // in the tree. We could cache the results to avoid making a string for
219   // every invocation.
220   std::string prefix = GetRulePrefix(settings);
221
222   if (type == SOURCE_C)
223     return prefix + "cc";
224   if (type == SOURCE_CC)
225     return prefix + "cxx";
226   if (type == SOURCE_M)
227     return prefix + "objc";
228   if (type == SOURCE_MM)
229     return prefix + "objcxx";
230   if (type == SOURCE_RC)
231     return prefix + "rc";
232   if (type == SOURCE_S)
233     return prefix + "cc";  // Assembly files just get compiled by CC.
234
235   // TODO(brettw) asm files.
236
237   // .obj files have no rules to make them (they're already built) so we return
238   // the enpty string for SOURCE_O.
239   return std::string();
240 }