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"
14 const char kLibDirWithSlash
[] = "lib/";
15 const char kObjectDirNoSlash
[] = "obj";
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] ==
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");
51 OutputFile
NinjaHelper::GetNinjaFileForToolchain(
52 const Settings
* settings
) const {
54 ret
.value().append(settings
->toolchain_output_subdir().value());
55 ret
.value().append("toolchain.ninja");
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(
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.
81 name
.append(target
->settings()->IsWin() ? "obj" : "o");
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
);
113 OutputFile
NinjaHelper::GetTargetOutputFile(const Target
* target
) const {
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).
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)
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
) {
141 extension
= GetExtensionForOutputType(target
->output_type(),
142 target
->settings()->target_os());
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
);
163 ret
.value().push_back('.');
164 ret
.value().append(extension
);
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
);
176 ret
.value().push_back('.');
177 ret
.value().append(extension
);
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
);
190 ret
.value().push_back('.');
191 ret
.value().append(extension
);
196 std::string
NinjaHelper::GetRulePrefix(const Settings
* settings
) const {
197 // Don't prefix the default toolchain so it looks prettier, prefix everything
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
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();