OLD | NEW |
---|---|
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "tools/gn/gyp_binary_target_writer.h" | 5 #include "tools/gn/gyp_binary_target_writer.h" |
6 | 6 |
7 #include <set> | 7 #include <set> |
8 | 8 |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/strings/string_util.h" | 10 #include "base/strings/string_util.h" |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
86 // The arch was passed as one GN string value, e.g. "-arch i386". Return | 86 // The arch was passed as one GN string value, e.g. "-arch i386". Return |
87 // the stuff following the space and delete the item. | 87 // the stuff following the space and delete the item. |
88 std::string ret = cur.substr(6); | 88 std::string ret = cur.substr(6); |
89 cflags->erase(cflags->begin() + i); | 89 cflags->erase(cflags->begin() + i); |
90 return ret; | 90 return ret; |
91 } | 91 } |
92 } | 92 } |
93 return std::string(); | 93 return std::string(); |
94 } | 94 } |
95 | 95 |
96 // Searches for -miphoneos-version-min, returns the resulting value, and | |
97 // removes it from the list. Returns the empty string if it's not found. | |
98 std::string GetIPhoneVersionMin(std::vector<std::string>* cflags) { | |
99 // Searches for the "-arch" option and returns the corresponding GYP value. | |
100 const char prefix[] = "-miphoneos-version-min="; | |
101 for (size_t i = 0; i < cflags->size(); i++) { | |
102 const std::string& cur = (*cflags)[i]; | |
103 if (StartsWithASCII(cur, prefix, true)) { | |
104 std::string result = cur.substr(arraysize(prefix) - 1); | |
105 cflags->erase(cflags->begin() + i); | |
106 return result; | |
107 } | |
108 } | |
109 return std::string(); | |
110 } | |
111 | |
96 // Finds all values from the given getter from all configs in the given list, | 112 // Finds all values from the given getter from all configs in the given list, |
97 // and adds them to the given result vector. | 113 // and adds them to the given result vector. |
98 template<typename T> | 114 template<typename T> |
99 void FillConfigListValues( | 115 void FillConfigListValues( |
100 const LabelConfigVector& configs, | 116 const LabelConfigVector& configs, |
101 const std::vector<T>& (ConfigValues::* getter)() const, | 117 const std::vector<T>& (ConfigValues::* getter)() const, |
102 std::vector<T>* result) { | 118 std::vector<T>* result) { |
103 for (size_t config_i = 0; config_i < configs.size(); config_i++) { | 119 for (size_t config_i = 0; config_i < configs.size(); config_i++) { |
104 const std::vector<T>& values = | 120 const std::vector<T>& values = |
105 (configs[config_i].ptr->config_values().*getter)(); | 121 (configs[config_i].ptr->config_values().*getter)(); |
106 for (size_t val_i = 0; val_i < values.size(); val_i++) | 122 for (size_t val_i = 0; val_i < values.size(); val_i++) |
107 result->push_back(values[val_i]); | 123 result->push_back(values[val_i]); |
108 } | 124 } |
109 } | 125 } |
110 | 126 |
127 bool IsClang(const Target* target) { | |
128 const Value* is_clang = | |
129 target->settings()->base_config()->GetValue("is_clang"); | |
130 return is_clang && is_clang->type() == Value::BOOLEAN && | |
131 is_clang->boolean_value(); | |
132 } | |
133 | |
134 bool IsIOS(const Target* target) { | |
135 const Value* is_ios = target->settings()->base_config()->GetValue("is_ios"); | |
136 return is_ios && is_ios->type() == Value::BOOLEAN && is_ios->boolean_value(); | |
137 } | |
138 | |
139 // Returns true if the current target is an iOS simulator build. | |
140 bool IsIOSSimulator(const std::vector<std::string>& cflags) { | |
141 // Search for the sysroot flag. We expect one flag to be the | |
142 // switch, and the following one to be the value. | |
Nico
2014/02/05 04:19:35
I think both -isysroot foo and -isysroot=foo might
| |
143 const char sysroot[] = "-isysroot"; | |
144 for (size_t i = 0; i < cflags.size(); i++) { | |
145 const std::string& cur = cflags[i]; | |
146 if (cur == sysroot) { | |
147 if (i == cflags.size() - 1) | |
148 return false; // No following value. | |
149 | |
150 // The argument is a file path, we check the prefix of the file name. | |
151 base::FilePath path(UTF8ToFilePath(cflags[i + 1])); | |
152 std::string path_file_part = FilePathToUTF8(path.BaseName()); | |
153 return StartsWithASCII(path_file_part, "iphonesimulator", false); | |
154 } | |
155 } | |
156 return false; | |
157 } | |
158 | |
111 } // namespace | 159 } // namespace |
112 | 160 |
113 GypBinaryTargetWriter::Flags::Flags() {} | 161 GypBinaryTargetWriter::Flags::Flags() {} |
114 GypBinaryTargetWriter::Flags::~Flags() {} | 162 GypBinaryTargetWriter::Flags::~Flags() {} |
115 | 163 |
116 GypBinaryTargetWriter::GypBinaryTargetWriter(const TargetGroup& group, | 164 GypBinaryTargetWriter::GypBinaryTargetWriter(const TargetGroup& group, |
117 const Toolchain* debug_toolchain, | 165 const Toolchain* debug_toolchain, |
118 const SourceDir& gyp_dir, | 166 const SourceDir& gyp_dir, |
119 std::ostream& out) | 167 std::ostream& out) |
120 : GypTargetWriter(group.get()->item()->AsTarget(), debug_toolchain, | 168 : GypTargetWriter(group.get()->item()->AsTarget(), debug_toolchain, |
(...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
375 indent + kExtraIndent * 2); | 423 indent + kExtraIndent * 2); |
376 | 424 |
377 // ...LD flags. | 425 // ...LD flags. |
378 // TODO(brettw) EnableUAC defaults to on and needs to be set. Also | 426 // TODO(brettw) EnableUAC defaults to on and needs to be set. Also |
379 // UACExecutionLevel and UACUIAccess depends on that and defaults to 0/false. | 427 // UACExecutionLevel and UACUIAccess depends on that and defaults to 0/false. |
380 WriteNamedArray("AdditionalOptions", flags.ldflags, 14); | 428 WriteNamedArray("AdditionalOptions", flags.ldflags, 14); |
381 Indent(indent + kExtraIndent) << "},\n"; | 429 Indent(indent + kExtraIndent) << "},\n"; |
382 Indent(indent) << "},\n"; | 430 Indent(indent) << "},\n"; |
383 } | 431 } |
384 | 432 |
385 void GypBinaryTargetWriter::WriteMacFlags(Flags& flags, int indent) { | 433 void GypBinaryTargetWriter::WriteMacFlags(const Target* target, |
434 Flags& flags, | |
435 int indent) { | |
386 WriteNamedArray("defines", flags.defines, indent); | 436 WriteNamedArray("defines", flags.defines, indent); |
387 WriteIncludeDirs(flags, indent); | 437 WriteIncludeDirs(flags, indent); |
388 | 438 |
389 // Libraries and library directories. | 439 // Libraries and library directories. |
390 EscapeOptions escape_options; | 440 EscapeOptions escape_options; |
391 escape_options.mode = ESCAPE_JSON; | 441 escape_options.mode = ESCAPE_JSON; |
392 if (!flags.lib_dirs.empty()) { | 442 if (!flags.lib_dirs.empty()) { |
393 Indent(indent + kExtraIndent) << "'library_dirs': ["; | 443 Indent(indent + kExtraIndent) << "'library_dirs': ["; |
394 for (size_t i = 0; i < flags.lib_dirs.size(); i++) { | 444 for (size_t i = 0; i < flags.lib_dirs.size(); i++) { |
395 out_ << " '"; | 445 out_ << " '"; |
(...skipping 11 matching lines...) Expand all Loading... | |
407 out_ << " '-l"; | 457 out_ << " '-l"; |
408 EscapeStringToStream(out_, flags.libs[i], escape_options); | 458 EscapeStringToStream(out_, flags.libs[i], escape_options); |
409 out_ << "',"; | 459 out_ << "',"; |
410 } | 460 } |
411 out_ << " ],\n"; | 461 out_ << " ],\n"; |
412 Indent(indent) << "},\n"; | 462 Indent(indent) << "},\n"; |
413 } | 463 } |
414 | 464 |
415 Indent(indent) << "'xcode_settings': {\n"; | 465 Indent(indent) << "'xcode_settings': {\n"; |
416 | 466 |
417 // Architecture. GYP uses this to write the -arch flag passed to the | 467 // Architecture. GYP reads this value and uses it to generate the -arch |
418 // compiler, it doesn't look at our -arch flag. So we need to specify it in | 468 // flag, so we always want to remove it from the cflags (which is a side |
419 // this special var and not in the cflags to avoid duplicates or conflicts. | 469 // effect of what GetMacArch does), even in cases where we don't use the |
470 // value (in the iOS arm below). | |
420 std::string arch = GetMacArch(&flags.cflags); | 471 std::string arch = GetMacArch(&flags.cflags); |
421 if (arch == "i386") | 472 if (IsIOS(target)) { |
422 Indent(indent + kExtraIndent) << "'ARCHS': [ 'i386' ],\n"; | 473 // When writing an iOS "target" (not host) target, we set VALID_ARCHS |
423 else if (arch == "x86_64") | 474 // instead of ARCHS and always use this hardcoded value. This matches the |
424 Indent(indent + kExtraIndent) << "'ARCHS': [ 'x86_64' ],\n"; | 475 // GYP build. |
476 Indent(indent + kExtraIndent) << "'VALID_ARCHS': 'armv7 i386',\n"; | |
477 | |
478 // Tell XCode to target both iPhone and iPad. GN has no such concept. | |
479 Indent(indent + kExtraIndent) << "'TARGETED_DEVICE_FAMILY': '1,2',\n"; | |
Nico
2014/02/05 04:19:35
Hm, hardcoding this stuff in the gn binary seems s
brettw
2014/02/05 04:29:30
Yeah. Is there a command line option this maps to?
Nico
2014/02/05 04:55:27
I think this is written into the UIDeviceFamily pl
| |
480 | |
481 if (IsIOSSimulator(flags.cflags)) { | |
482 Indent(indent + kExtraIndent) << "'SDKROOT': 'iphonesimulator',\n"; | |
483 } else { | |
484 Indent(indent + kExtraIndent) << "'SDKROOT': 'iphoneos',\n"; | |
485 std::string min_ver = GetIPhoneVersionMin(&flags.cflags); | |
486 if (!min_ver.empty()) | |
487 Indent(indent + kExtraIndent) << "'IPHONEOS_DEPLOYMENT_TARGET': '',\n"; | |
488 } | |
489 } else { | |
490 // When doing regular Mac and "host" iOS (which look like regular Mac) | |
491 // builds, we can set the ARCHS value to what's specified in the build. | |
492 if (arch == "i386") | |
493 Indent(indent + kExtraIndent) << "'ARCHS': [ 'i386' ],\n"; | |
494 else if (arch == "x86_64") | |
495 Indent(indent + kExtraIndent) << "'ARCHS': [ 'x86_64' ],\n"; | |
Nico
2014/02/05 04:19:36
remoting sets ARCHS to both i386, x86_64 I think (
brettw
2014/02/05 04:29:30
Okay, we'll have to deal with that when it comes u
Nico
2014/02/05 04:55:27
The commit message on how this is done in gyp/ninj
brettw
2014/02/05 06:18:53
I *think* the way to do this in GN would be to jus
| |
496 } | |
425 | 497 |
426 // C/C++ flags. | 498 // C/C++ flags. |
427 if (!flags.cflags.empty() || !flags.cflags_c.empty() || | 499 if (!flags.cflags.empty() || !flags.cflags_c.empty() || |
428 !flags.cflags_objc.empty()) { | 500 !flags.cflags_objc.empty()) { |
429 Indent(indent + kExtraIndent) << "'OTHER_CFLAGS': ["; | 501 Indent(indent + kExtraIndent) << "'OTHER_CFLAGS': ["; |
430 WriteArrayValues(out_, flags.cflags); | 502 WriteArrayValues(out_, flags.cflags); |
431 WriteArrayValues(out_, flags.cflags_c); | 503 WriteArrayValues(out_, flags.cflags_c); |
432 WriteArrayValues(out_, flags.cflags_objc); | 504 WriteArrayValues(out_, flags.cflags_objc); |
433 out_ << " ],\n"; | 505 out_ << " ],\n"; |
434 } | 506 } |
435 if (!flags.cflags.empty() || !flags.cflags_cc.empty() || | 507 if (!flags.cflags.empty() || !flags.cflags_cc.empty() || |
436 !flags.cflags_objcc.empty()) { | 508 !flags.cflags_objcc.empty()) { |
437 Indent(indent + kExtraIndent) << "'OTHER_CPLUSPLUSFLAGS': ["; | 509 Indent(indent + kExtraIndent) << "'OTHER_CPLUSPLUSFLAGS': ["; |
438 WriteArrayValues(out_, flags.cflags); | 510 WriteArrayValues(out_, flags.cflags); |
439 WriteArrayValues(out_, flags.cflags_cc); | 511 WriteArrayValues(out_, flags.cflags_cc); |
440 WriteArrayValues(out_, flags.cflags_objcc); | 512 WriteArrayValues(out_, flags.cflags_objcc); |
441 out_ << " ],\n"; | 513 out_ << " ],\n"; |
442 } | 514 } |
443 | 515 |
444 // Ld flags. Don't write these for static libraries. Otherwise, they'll be | 516 // Ld flags. Don't write these for static libraries. Otherwise, they'll be |
445 // passed to the library tool which doesn't expect it (the toolchain does | 517 // passed to the library tool which doesn't expect it (the toolchain does |
446 // not use ldflags so these are ignored in the normal build). | 518 // not use ldflags so these are ignored in the normal build). |
447 if (target_->output_type() != Target::STATIC_LIBRARY) | 519 if (target->output_type() != Target::STATIC_LIBRARY) |
448 WriteNamedArray("OTHER_LDFLAGS", flags.ldflags, indent + kExtraIndent); | 520 WriteNamedArray("OTHER_LDFLAGS", flags.ldflags, indent + kExtraIndent); |
449 | 521 |
450 // Write the compiler that XCode should use. When we're using clang, we want | 522 // Write the compiler that XCode should use. When we're using clang, we want |
451 // the custom one, otherwise don't add this and the default compiler will be | 523 // the custom one, otherwise don't add this and the default compiler will be |
452 // used. | 524 // used. |
453 // | 525 // |
454 // TODO(brettw) this is a hack. We could add a way for the GN build to set | 526 // TODO(brettw) this is a hack. We could add a way for the GN build to set |
455 // these values but as far as I can see this is the only use for them, so | 527 // these values but as far as I can see this is the only use for them, so |
456 // currently we manually check the build config's is_clang value. | 528 // currently we manually check the build config's is_clang value. |
457 const Value* is_clang = | 529 if (IsClang(target)) { |
458 target_->settings()->base_config()->GetValue("is_clang"); | |
459 if (is_clang && is_clang->type() == Value::BOOLEAN && | |
460 is_clang->boolean_value()) { | |
461 base::FilePath clang_path = | 530 base::FilePath clang_path = |
462 target_->settings()->build_settings()->GetFullPath(SourceFile( | 531 target_->settings()->build_settings()->GetFullPath(SourceFile( |
463 "//third_party/llvm-build/Release+Asserts/bin/clang")); | 532 "//third_party/llvm-build/Release+Asserts/bin/clang")); |
464 base::FilePath clang_pp_path = | 533 base::FilePath clang_pp_path = |
465 target_->settings()->build_settings()->GetFullPath(SourceFile( | 534 target_->settings()->build_settings()->GetFullPath(SourceFile( |
466 "//third_party/llvm-build/Release+Asserts/bin/clang++")); | 535 "//third_party/llvm-build/Release+Asserts/bin/clang++")); |
467 | 536 |
468 Indent(indent + kExtraIndent) | 537 Indent(indent + kExtraIndent) |
469 << "'CC': '" << FilePathToUTF8(clang_path) << "',\n"; | 538 << "'CC': '" << FilePathToUTF8(clang_path) << "',\n"; |
470 Indent(indent + kExtraIndent) | 539 Indent(indent + kExtraIndent) |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
526 if (host) { | 595 if (host) { |
527 // Write out the first part of the conditional. | 596 // Write out the first part of the conditional. |
528 Indent(indent) << kToolsetTargetCondition; | 597 Indent(indent) << kToolsetTargetCondition; |
529 extra_indent = kExtraIndent; | 598 extra_indent = kExtraIndent; |
530 } | 599 } |
531 | 600 |
532 // Always write the target flags (may or may not be inside a target | 601 // Always write the target flags (may or may not be inside a target |
533 // conditional). | 602 // conditional). |
534 { | 603 { |
535 Flags flags(FlagsFromTarget(target->item()->AsTarget())); | 604 Flags flags(FlagsFromTarget(target->item()->AsTarget())); |
536 WriteMacFlags(flags, indent + extra_indent); | 605 WriteMacFlags(target->item()->AsTarget(), flags, indent + extra_indent); |
537 } | 606 } |
538 | 607 |
539 // Now optionally write the host conditional arm. | 608 // Now optionally write the host conditional arm. |
540 if (host) { | 609 if (host) { |
541 Indent(indent) << kToolsetTargetElse; | 610 Indent(indent) << kToolsetTargetElse; |
542 Flags flags(FlagsFromTarget(host->item()->AsTarget())); | 611 Flags flags(FlagsFromTarget(host->item()->AsTarget())); |
543 WriteMacFlags(flags, indent + kExtraIndent); | 612 WriteMacFlags(host->item()->AsTarget(), flags, indent + kExtraIndent); |
544 Indent(indent) << kToolsetTargetEnd; | 613 Indent(indent) << kToolsetTargetEnd; |
545 } | 614 } |
546 } | 615 } |
547 | 616 |
548 void GypBinaryTargetWriter::WriteSources(const Target* target, int indent) { | 617 void GypBinaryTargetWriter::WriteSources(const Target* target, int indent) { |
549 Indent(indent) << "'sources': [\n"; | 618 Indent(indent) << "'sources': [\n"; |
550 | 619 |
551 const Target::FileList& sources = target->sources(); | 620 const Target::FileList& sources = target->sources(); |
552 for (size_t i = 0; i < sources.size(); i++) { | 621 for (size_t i = 0; i < sources.size(); i++) { |
553 const SourceFile& input_file = sources[i]; | 622 const SourceFile& input_file = sources[i]; |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
598 if (target_->direct_dependent_configs().empty()) | 667 if (target_->direct_dependent_configs().empty()) |
599 return; | 668 return; |
600 Indent(indent) << "'direct_dependent_settings': {\n"; | 669 Indent(indent) << "'direct_dependent_settings': {\n"; |
601 | 670 |
602 Flags flags(FlagsFromConfigList(target_->direct_dependent_configs())); | 671 Flags flags(FlagsFromConfigList(target_->direct_dependent_configs())); |
603 if (target_->settings()->IsLinux()) | 672 if (target_->settings()->IsLinux()) |
604 WriteLinuxFlags(flags, indent + kExtraIndent); | 673 WriteLinuxFlags(flags, indent + kExtraIndent); |
605 else if (target_->settings()->IsWin()) | 674 else if (target_->settings()->IsWin()) |
606 WriteVCFlags(flags, indent + kExtraIndent); | 675 WriteVCFlags(flags, indent + kExtraIndent); |
607 else if (target_->settings()->IsMac()) | 676 else if (target_->settings()->IsMac()) |
608 WriteMacFlags(flags, indent + kExtraIndent); | 677 WriteMacFlags(target_, flags, indent + kExtraIndent); |
609 Indent(indent) << "},\n"; | 678 Indent(indent) << "},\n"; |
610 } | 679 } |
611 | 680 |
612 void GypBinaryTargetWriter::WriteAllDependentSettings(int indent) { | 681 void GypBinaryTargetWriter::WriteAllDependentSettings(int indent) { |
613 if (target_->all_dependent_configs().empty()) | 682 if (target_->all_dependent_configs().empty()) |
614 return; | 683 return; |
615 Indent(indent) << "'all_dependent_settings': {\n"; | 684 Indent(indent) << "'all_dependent_settings': {\n"; |
616 | 685 |
617 Flags flags(FlagsFromConfigList(target_->all_dependent_configs())); | 686 Flags flags(FlagsFromConfigList(target_->all_dependent_configs())); |
618 if (target_->settings()->IsLinux()) | 687 if (target_->settings()->IsLinux()) |
619 WriteLinuxFlags(flags, indent + kExtraIndent); | 688 WriteLinuxFlags(flags, indent + kExtraIndent); |
620 else if (target_->settings()->IsWin()) | 689 else if (target_->settings()->IsWin()) |
621 WriteVCFlags(flags, indent + kExtraIndent); | 690 WriteVCFlags(flags, indent + kExtraIndent); |
622 else if (target_->settings()->IsMac()) | 691 else if (target_->settings()->IsMac()) |
623 WriteMacFlags(flags, indent + kExtraIndent); | 692 WriteMacFlags(target_, flags, indent + kExtraIndent); |
624 Indent(indent) << "},\n"; | 693 Indent(indent) << "},\n"; |
625 } | 694 } |
626 | 695 |
627 GypBinaryTargetWriter::Flags GypBinaryTargetWriter::FlagsFromTarget( | 696 GypBinaryTargetWriter::Flags GypBinaryTargetWriter::FlagsFromTarget( |
628 const Target* target) const { | 697 const Target* target) const { |
629 Flags ret; | 698 Flags ret; |
630 | 699 |
631 // Extracts a vector of the given type and name from the config values. | 700 // Extracts a vector of the given type and name from the config values. |
632 #define EXTRACT(type, name) \ | 701 #define EXTRACT(type, name) \ |
633 { \ | 702 { \ |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
689 return; | 758 return; |
690 | 759 |
691 EscapeOptions options; | 760 EscapeOptions options; |
692 options.mode = ESCAPE_JSON; | 761 options.mode = ESCAPE_JSON; |
693 | 762 |
694 Indent(indent) << "'" << name << "': ["; | 763 Indent(indent) << "'" << name << "': ["; |
695 WriteArrayValues(out_, values); | 764 WriteArrayValues(out_, values); |
696 out_ << " ],\n"; | 765 out_ << " ],\n"; |
697 } | 766 } |
698 | 767 |
OLD | NEW |