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_target_writer.h" |
| 6 |
| 7 #include <fstream> |
| 8 #include <sstream> |
| 9 |
| 10 #include "base/file_util.h" |
| 11 #include "base/logging.h" |
| 12 #include "base/strings/string_util.h" |
| 13 #include "tools/gn/config_values_extractors.h" |
| 14 #include "tools/gn/err.h" |
| 15 #include "tools/gn/escape.h" |
| 16 #include "tools/gn/file_template.h" |
| 17 #include "tools/gn/location.h" |
| 18 #include "tools/gn/path_output.h" |
| 19 #include "tools/gn/scheduler.h" |
| 20 #include "tools/gn/string_utils.h" |
| 21 #include "tools/gn/target.h" |
| 22 |
| 23 namespace { |
| 24 |
| 25 static const char kCustomTargetSourceKey[] = "{{source}}"; |
| 26 static const char kCustomTargetSourceNamePartKey[] = "{{source_name_part}}"; |
| 27 |
| 28 struct DefineWriter { |
| 29 void operator()(const std::string& s, std::ostream& out) const { |
| 30 out << " -D" << s; |
| 31 } |
| 32 }; |
| 33 |
| 34 struct IncludeWriter { |
| 35 IncludeWriter(PathOutput& path_output, |
| 36 const NinjaHelper& h) |
| 37 : helper(h), |
| 38 path_output_(path_output), |
| 39 old_inhibit_quoting_(path_output.inhibit_quoting()) { |
| 40 // Inhibit quoting since we'll put quotes around the whole thing ourselves. |
| 41 // Since we're writing in NINJA escaping mode, this won't actually do |
| 42 // anything, but I think we may need to change to shell-and-then-ninja |
| 43 // escaping for this in the future. |
| 44 path_output_.set_inhibit_quoting(true); |
| 45 } |
| 46 ~IncludeWriter() { |
| 47 path_output_.set_inhibit_quoting(old_inhibit_quoting_); |
| 48 } |
| 49 |
| 50 void operator()(const SourceDir& d, std::ostream& out) const { |
| 51 out << " \"-I"; |
| 52 // It's important not to include the trailing slash on directories or on |
| 53 // Windows it will be a backslash and the compiler might think we're |
| 54 // escaping the quote! |
| 55 path_output_.WriteDir(out, d, PathOutput::DIR_NO_LAST_SLASH); |
| 56 out << "\""; |
| 57 } |
| 58 |
| 59 const NinjaHelper& helper; |
| 60 PathOutput& path_output_; |
| 61 bool old_inhibit_quoting_; // So we can put the PathOutput back. |
| 62 }; |
| 63 |
| 64 } // namespace |
| 65 |
| 66 NinjaTargetWriter::NinjaTargetWriter(const Target* target, std::ostream& out) |
| 67 : settings_(target->settings()), |
| 68 target_(target), |
| 69 out_(out), |
| 70 path_output_(settings_->build_settings()->build_dir(), |
| 71 ESCAPE_NINJA, true), |
| 72 helper_(settings_->build_settings()) { |
| 73 } |
| 74 |
| 75 NinjaTargetWriter::~NinjaTargetWriter() { |
| 76 } |
| 77 |
| 78 void NinjaTargetWriter::Run() { |
| 79 out_ << "arch = environment.x86\n"; |
| 80 |
| 81 if (target_->output_type() == Target::COPY_FILES) { |
| 82 WriteCopyRules(); |
| 83 } else if (target_->output_type() == Target::CUSTOM) { |
| 84 WriteCustomRules(); |
| 85 } else { |
| 86 WriteCompilerVars(); |
| 87 |
| 88 std::vector<OutputFile> obj_files; |
| 89 WriteSources(&obj_files); |
| 90 |
| 91 WriteLinkerStuff(obj_files); |
| 92 } |
| 93 } |
| 94 |
| 95 // static |
| 96 void NinjaTargetWriter::RunAndWriteFile(const Target* target) { |
| 97 if (target->output_type() == Target::NONE) |
| 98 return; |
| 99 |
| 100 const Settings* settings = target->settings(); |
| 101 NinjaHelper helper(settings->build_settings()); |
| 102 |
| 103 base::FilePath ninja_file(settings->build_settings()->GetFullPath( |
| 104 helper.GetNinjaFileForTarget(target).GetSourceFile( |
| 105 settings->build_settings()))); |
| 106 |
| 107 file_util::CreateDirectory(ninja_file.DirName()); |
| 108 |
| 109 // It's rediculously faster to write to a string and then write that to |
| 110 // disk in one operation than to use an fstream here. |
| 111 std::stringstream file; |
| 112 if (file.fail()) { |
| 113 g_scheduler->FailWithError( |
| 114 Err(Location(), "Error writing ninja file.", |
| 115 "Unable to open \"" + FilePathToUTF8(ninja_file) + "\"\n" |
| 116 "for writing.")); |
| 117 return; |
| 118 } |
| 119 |
| 120 NinjaTargetWriter gen(target, file); |
| 121 gen.Run(); |
| 122 |
| 123 std::string contents = file.str(); |
| 124 file_util::WriteFile(ninja_file, contents.c_str(), contents.size()); |
| 125 } |
| 126 |
| 127 void NinjaTargetWriter::WriteCopyRules() { |
| 128 // The dest dir should be inside the output dir so we can just remove the |
| 129 // prefix and get ninja-relative paths. |
| 130 const std::string& output_dir = |
| 131 settings_->build_settings()->build_dir().value(); |
| 132 const std::string& dest_dir = target_->destdir().value(); |
| 133 DCHECK(StartsWithASCII(dest_dir, output_dir, true)); |
| 134 std::string relative_dest_dir(&dest_dir[output_dir.size()], |
| 135 dest_dir.size() - output_dir.size()); |
| 136 |
| 137 const Target::FileList& sources = target_->sources(); |
| 138 std::vector<OutputFile> dest_files; |
| 139 dest_files.reserve(sources.size()); |
| 140 |
| 141 // Write out rules for each file copied. |
| 142 for (size_t i = 0; i < sources.size(); i++) { |
| 143 const SourceFile& input_file = sources[i]; |
| 144 |
| 145 // The files should have the same name but in the dest dir. |
| 146 base::StringPiece name_part = FindFilename(&input_file.value()); |
| 147 OutputFile dest_file(relative_dest_dir); |
| 148 AppendStringPiece(&dest_file.value(), name_part); |
| 149 |
| 150 dest_files.push_back(dest_file); |
| 151 |
| 152 out_ << "build "; |
| 153 path_output_.WriteFile(out_, dest_file); |
| 154 out_ << ": copy "; |
| 155 path_output_.WriteFile(out_, input_file); |
| 156 out_ << std::endl; |
| 157 } |
| 158 |
| 159 // Write out the rule for the target to copy all of them. |
| 160 out_ << std::endl << "build "; |
| 161 path_output_.WriteFile(out_, helper_.GetTargetOutputFile(target_)); |
| 162 out_ << ": stamp"; |
| 163 for (size_t i = 0; i < dest_files.size(); i++) { |
| 164 out_ << " "; |
| 165 path_output_.WriteFile(out_, dest_files[i]); |
| 166 } |
| 167 out_ << std::endl; |
| 168 |
| 169 // TODO(brettw) need some kind of stamp file for depending on this, as well |
| 170 // as order_only=prebuild. |
| 171 } |
| 172 |
| 173 void NinjaTargetWriter::WriteCustomRules() { |
| 174 // Make a unique name for this rule. |
| 175 std::string target_label = target_->label().GetUserVisibleName(true); |
| 176 std::string custom_rule_name(target_label); |
| 177 ReplaceChars(custom_rule_name, ":/()", "_", &custom_rule_name); |
| 178 custom_rule_name.append("_rule"); |
| 179 |
| 180 // Run the script from the dir of the BUILD file. This has no trailing |
| 181 // slash. |
| 182 const SourceDir& script_cd = target_->label().dir(); |
| 183 std::string script_cd_to_root = InvertDir(script_cd); |
| 184 if (script_cd_to_root.empty()) { |
| 185 script_cd_to_root = "."; |
| 186 } else { |
| 187 // Remove trailing slash |
| 188 DCHECK(script_cd_to_root[script_cd_to_root.size() - 1] == '/'); |
| 189 script_cd_to_root.resize(script_cd_to_root.size() - 1); |
| 190 } |
| 191 |
| 192 std::string script_relative_to_cd = |
| 193 script_cd_to_root + target_->script().value(); |
| 194 |
| 195 bool no_sources = target_->sources().empty(); |
| 196 |
| 197 // Use a unique name for the response file when there are multiple build |
| 198 // steps so that they don't stomp on each other. |
| 199 std::string rspfile = custom_rule_name; |
| 200 if (!no_sources) |
| 201 rspfile += ".$unique_name"; |
| 202 rspfile += ".rsp"; |
| 203 |
| 204 // First write the custom rule. |
| 205 out_ << "rule " << custom_rule_name << std::endl; |
| 206 out_ << " command = $pythonpath gyp-win-tool action-wrapper $arch " |
| 207 << rspfile << " "; |
| 208 path_output_.WriteDir(out_, script_cd, PathOutput::DIR_NO_LAST_SLASH); |
| 209 out_ << std::endl; |
| 210 out_ << " description = CUSTOM " << target_label << std::endl; |
| 211 out_ << " restat = 1" << std::endl; |
| 212 out_ << " rspfile = " << rspfile << std::endl; |
| 213 |
| 214 // The build command goes in the rsp file. |
| 215 out_ << " rspfile_content = $pythonpath " << script_relative_to_cd; |
| 216 for (size_t i = 0; i < target_->script_args().size(); i++) { |
| 217 const std::string& arg = target_->script_args()[i]; |
| 218 out_ << " "; |
| 219 WriteCustomArg(arg); |
| 220 } |
| 221 out_ << std::endl << std::endl; |
| 222 |
| 223 // Precompute the common dependencies for each step. This includes the |
| 224 // script itself (changing the script should force a rebuild) and any data |
| 225 // files. |
| 226 std::ostringstream common_deps_stream; |
| 227 path_output_.WriteFile(common_deps_stream, target_->script()); |
| 228 const Target::FileList& datas = target_->data(); |
| 229 for (size_t i = 0; i < datas.size(); i++) { |
| 230 common_deps_stream << " "; |
| 231 path_output_.WriteFile(common_deps_stream, datas[i]); |
| 232 } |
| 233 const std::string& common_deps = common_deps_stream.str(); |
| 234 |
| 235 // Collects all output files for writing below. |
| 236 std::vector<OutputFile> output_files; |
| 237 |
| 238 if (no_sources) { |
| 239 // No sources, write a rule that invokes the script once with the |
| 240 // outputs as outputs, and the data as inputs. |
| 241 out_ << "build"; |
| 242 const Target::FileList& outputs = target_->outputs(); |
| 243 for (size_t i = 0; i < outputs.size(); i++) { |
| 244 OutputFile output_path( |
| 245 RemovePrefix(outputs[i].value(), |
| 246 settings_->build_settings()->build_dir().value())); |
| 247 output_files.push_back(output_path); |
| 248 out_ << " "; |
| 249 path_output_.WriteFile(out_, output_path); |
| 250 } |
| 251 out_ << ": " << custom_rule_name << " " << common_deps << std::endl; |
| 252 } else { |
| 253 // Write separate rules for each input source file. |
| 254 WriteCustomSourceRules(custom_rule_name, common_deps, script_cd, |
| 255 script_cd_to_root, &output_files); |
| 256 } |
| 257 out_ << std::endl; |
| 258 |
| 259 // Last write a stamp rule to collect all outputs. |
| 260 out_ << "build "; |
| 261 path_output_.WriteFile(out_, helper_.GetTargetOutputFile(target_)); |
| 262 out_ << ": stamp"; |
| 263 for (size_t i = 0; i < output_files.size(); i++) { |
| 264 out_ << " "; |
| 265 path_output_.WriteFile(out_, output_files[i]); |
| 266 } |
| 267 out_ << std::endl; |
| 268 } |
| 269 |
| 270 void NinjaTargetWriter::WriteCustomArg(const std::string& arg) { |
| 271 // This can be optimized if it's called a lot. |
| 272 EscapeOptions options; |
| 273 options.mode = ESCAPE_NINJA; |
| 274 std::string output_str = EscapeString(arg, options); |
| 275 |
| 276 // Do this substitution after escaping our our $ will be escaped (which we |
| 277 // don't want). |
| 278 ReplaceSubstringsAfterOffset(&output_str, 0, FileTemplate::kSource, |
| 279 "${source}"); |
| 280 ReplaceSubstringsAfterOffset(&output_str, 0, FileTemplate::kSourceNamePart, |
| 281 "${source_name_part}"); |
| 282 out_ << output_str; |
| 283 } |
| 284 |
| 285 void NinjaTargetWriter::WriteCustomSourceRules( |
| 286 const std::string& custom_rule_name, |
| 287 const std::string& common_deps, |
| 288 const SourceDir& script_cd, |
| 289 const std::string& script_cd_to_root, |
| 290 std::vector<OutputFile>* output_files) { |
| 291 // Construct the template for generating the output files from each source. |
| 292 const Target::FileList& outputs = target_->outputs(); |
| 293 std::vector<std::string> output_template_args; |
| 294 for (size_t i = 0; i < outputs.size(); i++) { |
| 295 // All outputs should be in the output dir. |
| 296 output_template_args.push_back( |
| 297 RemovePrefix(outputs[i].value(), |
| 298 settings_->build_settings()->build_dir().value())); |
| 299 } |
| 300 FileTemplate output_template(output_template_args); |
| 301 |
| 302 // Prevent re-allocating each time by initializing outside the loop. |
| 303 std::vector<std::string> output_template_result; |
| 304 |
| 305 // Path output formatter for wrigin source paths passed to the script. |
| 306 PathOutput script_source_path_output(script_cd, ESCAPE_SHELL, true); |
| 307 |
| 308 const Target::FileList& sources = target_->sources(); |
| 309 for (size_t i = 0; i < sources.size(); i++) { |
| 310 // Write outputs for this source file computed by the template. |
| 311 out_ << "build"; |
| 312 output_template.ApplyString(sources[i].value(), &output_template_result); |
| 313 for (size_t out_i = 0; out_i < output_template_result.size(); out_i++) { |
| 314 OutputFile output_path(output_template_result[out_i]); |
| 315 output_files->push_back(output_path); |
| 316 out_ << " "; |
| 317 path_output_.WriteFile(out_, output_path); |
| 318 } |
| 319 |
| 320 out_ << ": " << custom_rule_name |
| 321 << " " << common_deps |
| 322 << " "; |
| 323 path_output_.WriteFile(out_, sources[i]); |
| 324 out_ << std::endl; |
| 325 |
| 326 out_ << " unique_name = " << i << std::endl; |
| 327 |
| 328 // The source file here should be relative to the script directory since |
| 329 // this is the variable passed to the script. Here we slightly abuse the |
| 330 // OutputFile object by putting a non-output-relative path in it to signal |
| 331 // that the PathWriter should not prepend directories. |
| 332 out_ << " source = "; |
| 333 script_source_path_output.WriteFile(out_, sources[i]); |
| 334 out_ << std::endl; |
| 335 |
| 336 out_ << " source_name_part = " |
| 337 << FindFilenameNoExtension(&sources[i].value()).as_string() |
| 338 << std::endl; |
| 339 } |
| 340 } |
| 341 |
| 342 void NinjaTargetWriter::WriteCompilerVars() { |
| 343 // Defines. |
| 344 out_ << "defines ="; |
| 345 RecursiveTargetConfigToStream(target_, &ConfigValues::defines, |
| 346 DefineWriter(), out_); |
| 347 out_ << std::endl; |
| 348 |
| 349 // Includes. |
| 350 out_ << "includes ="; |
| 351 RecursiveTargetConfigToStream(target_, &ConfigValues::includes, |
| 352 IncludeWriter(path_output_, helper_), out_); |
| 353 |
| 354 out_ << std::endl; |
| 355 |
| 356 // C flags and friends. |
| 357 out_ << "cflags ="; |
| 358 RecursiveTargetConfigStringsToStream(target_, &ConfigValues::cflags, out_); |
| 359 out_ << std::endl; |
| 360 out_ << "cflags_c ="; |
| 361 RecursiveTargetConfigStringsToStream(target_, &ConfigValues::cflags_c, out_); |
| 362 out_ << std::endl; |
| 363 out_ << "cflags_cc ="; |
| 364 RecursiveTargetConfigStringsToStream(target_, &ConfigValues::cflags_cc, out_); |
| 365 out_ << std::endl; |
| 366 |
| 367 out_ << std::endl; |
| 368 } |
| 369 |
| 370 void NinjaTargetWriter::WriteSources( |
| 371 std::vector<OutputFile>* object_files) { |
| 372 const Target::FileList& sources = target_->sources(); |
| 373 object_files->reserve(sources.size()); |
| 374 |
| 375 for (size_t i = 0; i < sources.size(); i++) { |
| 376 const SourceFile& input_file = sources[i]; |
| 377 |
| 378 SourceFileType input_file_type = GetSourceFileType(input_file, |
| 379 settings_->target_os()); |
| 380 if (input_file_type == SOURCE_UNKNOWN) |
| 381 continue; // Skip unknown file types. |
| 382 const char* command = GetCommandForSourceType(input_file_type); |
| 383 if (!command) |
| 384 continue; // Skip files not needing compilation. |
| 385 |
| 386 OutputFile output_file = helper_.GetOutputFileForSource( |
| 387 target_, input_file, input_file_type); |
| 388 object_files->push_back(output_file); |
| 389 |
| 390 out_ << "build "; |
| 391 path_output_.WriteFile(out_, output_file); |
| 392 out_ << ": " << command << " "; |
| 393 path_output_.WriteFile(out_, input_file); |
| 394 out_ << std::endl; |
| 395 } |
| 396 out_ << std::endl; |
| 397 } |
| 398 |
| 399 void NinjaTargetWriter::WriteLinkerStuff( |
| 400 const std::vector<OutputFile>& object_files) { |
| 401 // Manifest file on Windows. |
| 402 // TODO(brettw) this seems not to be necessary for static libs, skip in |
| 403 // that case? |
| 404 OutputFile windows_manifest; |
| 405 if (settings_->IsWin()) { |
| 406 windows_manifest.value().assign(helper_.GetTargetOutputDir(target_)); |
| 407 windows_manifest.value().append(target_->label().name()); |
| 408 windows_manifest.value().append(".intermediate.manifest"); |
| 409 out_ << "manifests = "; |
| 410 path_output_.WriteFile(out_, windows_manifest); |
| 411 out_ << std::endl; |
| 412 } |
| 413 |
| 414 // Linker flags, append manifest flag on Windows to reference our file. |
| 415 out_ << "ldflags ="; |
| 416 RecursiveTargetConfigStringsToStream(target_, &ConfigValues::ldflags, out_); |
| 417 if (settings_->IsWin()) |
| 418 out_ << " /MANIFEST /ManifestFile:"; |
| 419 path_output_.WriteFile(out_, windows_manifest); |
| 420 { // HACK ERASEME BRETTW FIXME |
| 421 out_ << " /DEBUG /MACHINE:X86 /LIBPATH:\"C:\\Program Files (x86)\\Windows Ki
ts\\8.0\\Lib\\win8\\um\\x86\" /DELAYLOAD:dbghelp.dll /DELAYLOAD:dwmapi.dll /DELA
YLOAD:shell32.dll /DELAYLOAD:uxtheme.dll /safeseh /dynamicbase /ignore:4199 /ign
ore:4221 /nxcompat /SUBSYSTEM:CONSOLE /INCREMENTAL /FIXED:NO /DYNAMICBASE:NO win
inet.lib dnsapi.lib version.lib msimg32.lib ws2_32.lib usp10.lib psapi.lib dbghe
lp.lib winmm.lib shlwapi.lib kernel32.lib gdi32.lib winspool.lib comdlg32.lib ad
vapi32.lib shell32.lib ole32.lib oleaut32.lib user32.lib uuid.lib odbc32.lib odb
ccp32.lib delayimp.lib /NXCOMPAT"; |
| 422 } |
| 423 out_ << std::endl; |
| 424 |
| 425 // Libraries to link. |
| 426 out_ << "libs =" << std::endl; |
| 427 |
| 428 // The external output file is the one that other libs depend on. |
| 429 OutputFile external_output_file = helper_.GetTargetOutputFile(target_); |
| 430 |
| 431 // The internal output file is the "main thing" we think we're making. In |
| 432 // the case of shared libraries, this is the shared library and the external |
| 433 // output file is the import library. In other cases, the internal one and |
| 434 // the external one are the same. |
| 435 OutputFile internal_output_file; |
| 436 if (target_->output_type() == Target::SHARED_LIBRARY) { |
| 437 if (settings_->IsWin()) { |
| 438 internal_output_file = OutputFile(target_->label().name() + ".dll"); |
| 439 } else { |
| 440 NOTREACHED(); // TODO(brettw) write this. |
| 441 } |
| 442 } else { |
| 443 internal_output_file = external_output_file; |
| 444 } |
| 445 |
| 446 // TODO(brettw) should we append data files to this? |
| 447 |
| 448 // In Python see "self.ninja.build(output, command, input," |
| 449 out_ << "build "; |
| 450 path_output_.WriteFile(out_, internal_output_file); |
| 451 if (external_output_file != internal_output_file) { |
| 452 out_ << " "; |
| 453 path_output_.WriteFile(out_, external_output_file); |
| 454 } |
| 455 out_ << ": " << GetCommandForTargetType(); |
| 456 for (size_t i = 0; i < object_files.size(); i++) { |
| 457 out_ << " "; |
| 458 path_output_.WriteFile(out_, object_files[i]); |
| 459 } |
| 460 |
| 461 if (target_->output_type() == Target::EXECUTABLE || |
| 462 target_->output_type() == Target::SHARED_LIBRARY || |
| 463 target_->output_type() == Target::LOADABLE_MODULE) { |
| 464 const std::vector<const Target*>& deps = target_->deps(); |
| 465 const std::set<const Target*>& inherited = target_->inherited_libraries(); |
| 466 |
| 467 // Now append linkable libraries to the linker command. |
| 468 for (size_t i = 0; i < deps.size(); i++) { |
| 469 if (deps[i]->IsLinkable() && |
| 470 inherited.find(deps[i]) == inherited.end()) { |
| 471 out_ << " "; |
| 472 path_output_.WriteFile(out_, |
| 473 helper_.GetTargetOutputFile(target_->deps()[i])); |
| 474 } |
| 475 } |
| 476 for (std::set<const Target*>::const_iterator i = inherited.begin(); |
| 477 i != inherited.end(); ++i) { |
| 478 out_ << " "; |
| 479 path_output_.WriteFile(out_, helper_.GetTargetOutputFile(*i)); |
| 480 } |
| 481 } |
| 482 out_ << std::endl; |
| 483 |
| 484 if (target_->output_type() == Target::SHARED_LIBRARY) { |
| 485 out_ << " soname = "; |
| 486 path_output_.WriteFile(out_, internal_output_file); |
| 487 out_ << std::endl; |
| 488 |
| 489 out_ << " lib = "; |
| 490 path_output_.WriteFile(out_, internal_output_file); |
| 491 out_ << std::endl; |
| 492 |
| 493 out_ << " dll = "; |
| 494 path_output_.WriteFile(out_, internal_output_file); |
| 495 out_ << std::endl; |
| 496 |
| 497 if (settings_->IsWin()) { |
| 498 out_ << " implibflag = /IMPLIB:"; |
| 499 path_output_.WriteFile(out_, external_output_file); |
| 500 out_ << std::endl; |
| 501 } |
| 502 } |
| 503 |
| 504 // TODO(brettw) postbuild steps here. |
| 505 |
| 506 out_ << std::endl; |
| 507 } |
| 508 |
| 509 const char* NinjaTargetWriter::GetCommandForSourceType( |
| 510 SourceFileType type) const { |
| 511 if (type == SOURCE_C) |
| 512 return "cc"; |
| 513 if (type == SOURCE_CC) |
| 514 return "cxx"; |
| 515 |
| 516 // TODO(brettw) asm files. |
| 517 |
| 518 if (settings_->IsMac()) { |
| 519 if (type == SOURCE_M) |
| 520 return "objc"; |
| 521 if (type == SOURCE_MM) |
| 522 return "objcxx"; |
| 523 } |
| 524 |
| 525 if (settings_->IsWin()) { |
| 526 if (type == SOURCE_RC) |
| 527 return "rc"; |
| 528 } |
| 529 |
| 530 // TODO(brettw) stuff about "S" files on non-Windows. |
| 531 return NULL; |
| 532 } |
| 533 |
| 534 const char* NinjaTargetWriter::GetCommandForTargetType() const { |
| 535 if (target_->output_type() == Target::NONE) { |
| 536 NOTREACHED(); |
| 537 return ""; |
| 538 } |
| 539 |
| 540 if (target_->output_type() == Target::STATIC_LIBRARY) { |
| 541 // TODO(brettw) stuff about standalong static libraryes on Unix in |
| 542 // WriteTarget in the Python one, and lots of postbuild steps. |
| 543 return "alink"; |
| 544 } |
| 545 |
| 546 if (target_->output_type() == Target::SHARED_LIBRARY) |
| 547 return "solink"; |
| 548 |
| 549 return "link"; |
| 550 } |
OLD | NEW |