| 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 |