- add sources.
[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 "tools/gn/filesystem_utils.h"
9 #include "tools/gn/string_utils.h"
10 #include "tools/gn/target.h"
11
12 namespace {
13
14 const char kLibDirWithSlash[] = "lib/";
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   ConvertPathToSystem(&build_to_src_system_no_last_slash_);
29 }
30
31 NinjaHelper::~NinjaHelper() {
32 }
33
34 std::string NinjaHelper::GetTopleveOutputDir() const {
35   return kObjectDirNoSlash;
36 }
37
38 std::string NinjaHelper::GetTargetOutputDir(const Target* target) const {
39   return kObjectDirNoSlash + target->label().dir().SourceAbsoluteWithOneSlash();
40 }
41
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;
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     case SOURCE_H:
90     case SOURCE_UNKNOWN:
91       NOTREACHED();
92       return OutputFile();
93   }
94
95   // Use the scheme <path>/<target>.<name>.<extension> so that all output
96   // names are unique to different targets.
97
98   // This will look like "obj" or "toolchain_name/obj".
99   OutputFile ret(target->settings()->toolchain_output_subdir());
100   ret.value().append(kObjectDirNoSlash);
101
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));
107
108   ret.value().append(target->label().name());
109   ret.value().append(".");
110   ret.value().append(name);
111   return ret;
112 }
113
114 OutputFile NinjaHelper::GetTargetOutputFile(const Target* target) const {
115   OutputFile ret;
116
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();
120
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 = "";
132
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());
142   }
143
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());
147
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);
161     }
162     return ret;
163   }
164
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);
174     }
175     return ret;
176   }
177
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);
188   }
189   return ret;
190 }
191
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() + "_";
198 }
199
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);
206
207   if (type == SOURCE_C)
208     return prefix + "cc";
209   if (type == SOURCE_CC)
210     return prefix + "cxx";
211
212   // TODO(brettw) asm files.
213
214   if (settings->IsMac()) {
215     if (type == SOURCE_M)
216       return prefix + "objc";
217     if (type == SOURCE_MM)
218       return prefix + "objcxx";
219   }
220
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.
227   }
228
229   return std::string();
230 }