OLD | NEW |
| (Empty) |
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 } | |
OLD | NEW |