| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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/xcode_writer.h" | 5 #include "tools/gn/xcode_writer.h" |
| 6 | 6 |
| 7 #include <iomanip> | 7 #include <iomanip> |
| 8 #include <map> | 8 #include <map> |
| 9 #include <memory> | 9 #include <memory> |
| 10 #include <sstream> | 10 #include <sstream> |
| 11 #include <string> | 11 #include <string> |
| 12 #include <utility> | 12 #include <utility> |
| 13 | 13 |
| 14 #include "base/environment.h" | 14 #include "base/environment.h" |
| 15 #include "base/logging.h" | 15 #include "base/logging.h" |
| 16 #include "base/sha1.h" | 16 #include "base/sha1.h" |
| 17 #include "base/strings/string_number_conversions.h" | 17 #include "base/strings/string_number_conversions.h" |
| 18 #include "base/strings/string_util.h" | 18 #include "base/strings/string_util.h" |
| 19 #include "tools/gn/args.h" | 19 #include "tools/gn/args.h" |
| 20 #include "tools/gn/build_settings.h" | 20 #include "tools/gn/build_settings.h" |
| 21 #include "tools/gn/builder.h" | 21 #include "tools/gn/builder.h" |
| 22 #include "tools/gn/commands.h" | 22 #include "tools/gn/commands.h" |
| 23 #include "tools/gn/config_values_extractors.h" |
| 23 #include "tools/gn/deps_iterator.h" | 24 #include "tools/gn/deps_iterator.h" |
| 24 #include "tools/gn/filesystem_utils.h" | 25 #include "tools/gn/filesystem_utils.h" |
| 25 #include "tools/gn/settings.h" | 26 #include "tools/gn/settings.h" |
| 26 #include "tools/gn/source_file.h" | 27 #include "tools/gn/source_file.h" |
| 27 #include "tools/gn/target.h" | 28 #include "tools/gn/target.h" |
| 28 #include "tools/gn/value.h" | 29 #include "tools/gn/value.h" |
| 29 #include "tools/gn/variables.h" | 30 #include "tools/gn/variables.h" |
| 30 #include "tools/gn/xcode_object.h" | 31 #include "tools/gn/xcode_object.h" |
| 31 | 32 |
| 32 namespace { | 33 namespace { |
| (...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 309 break; | 310 break; |
| 310 | 311 |
| 311 default: | 312 default: |
| 312 break; | 313 break; |
| 313 } | 314 } |
| 314 } | 315 } |
| 315 | 316 |
| 316 projects_.push_back(std::move(main_project)); | 317 projects_.push_back(std::move(main_project)); |
| 317 } | 318 } |
| 318 | 319 |
| 320 namespace { |
| 321 |
| 322 template <typename T> |
| 323 void SortAndRemoveDuplicates(std::vector<T>& vec) { |
| 324 std::sort(vec.begin(), vec.end()); |
| 325 vec.erase(std::unique(vec.begin(), vec.end()), vec.end()); |
| 326 } |
| 327 |
| 328 template <typename T> |
| 329 std::vector<T> IntersectSortedVectors(const std::vector<T>& vec, |
| 330 const std::vector<T>& vec2) { |
| 331 std::vector<T> intersection; |
| 332 std::set_intersection(vec.begin(), vec.end(), vec2.begin(), vec2.end(), |
| 333 std::back_inserter(intersection)); |
| 334 return intersection; |
| 335 } |
| 336 |
| 337 template <typename T> |
| 338 std::vector<T> ExcludeSortedVectors(const std::vector<T>& from, |
| 339 const std::vector<T>& what) { |
| 340 std::vector<T> difference; |
| 341 std::set_difference(from.begin(), from.end(), what.begin(), what.end(), |
| 342 std::back_inserter(difference)); |
| 343 return difference; |
| 344 } |
| 345 |
| 346 void ExtractDialect(std::string& res, |
| 347 const std::vector<std::string>& flags, |
| 348 bool cc) { |
| 349 for (const auto& flag : flags) { |
| 350 if (res.empty() && flag.compare(0, 5, "-std=") == 0) { |
| 351 res = flag; |
| 352 } |
| 353 if (!res.empty()) { |
| 354 break; |
| 355 } |
| 356 } |
| 357 |
| 358 // we're looking for c++ dialect, it must have + in name |
| 359 if (cc && res.find('+') == std::string::npos) |
| 360 res.clear(); |
| 361 |
| 362 // we're looking for c dialect, it must not have + in name |
| 363 if (!cc && res.find('+') != std::string::npos) |
| 364 res.clear(); |
| 365 } |
| 366 |
| 367 void PrepareBuildAttributes(const std::vector<const Target*>& indexed_targets, |
| 368 const SourceDir& root_build_dir, |
| 369 std::map<SourceFile, std::string> & cflags, |
| 370 PBXAttributes & attributes) { |
| 371 std::vector<SourceDir> common_includes; |
| 372 std::vector<std::string> common_defines; |
| 373 |
| 374 for (const auto* target : indexed_targets) { |
| 375 std::vector<SourceDir> target_includes; |
| 376 std::vector<std::string> target_defines; |
| 377 |
| 378 for (ConfigValuesIterator it(target); !it.done(); it.Next()) { |
| 379 target_includes.insert(target_includes.end(), |
| 380 it.cur().include_dirs().begin(), |
| 381 it.cur().include_dirs().end()); |
| 382 target_defines.insert(target_defines.end(), |
| 383 it.cur().defines().begin(), |
| 384 it.cur().defines().end()); |
| 385 } |
| 386 SortAndRemoveDuplicates(target_includes); |
| 387 SortAndRemoveDuplicates(target_defines); |
| 388 |
| 389 if (target == indexed_targets.front()) { |
| 390 common_includes = std::move(target_includes); |
| 391 common_defines = std::move(target_defines); |
| 392 } else { |
| 393 if (common_includes.empty() && common_defines.empty()) |
| 394 break; |
| 395 common_includes = IntersectSortedVectors(common_includes, |
| 396 target_includes); |
| 397 common_defines = IntersectSortedVectors(common_defines, |
| 398 target_defines); |
| 399 } |
| 400 } |
| 401 |
| 402 for (const auto* target : indexed_targets) { |
| 403 std::vector<SourceDir> target_includes; |
| 404 std::vector<std::string> target_defines; |
| 405 |
| 406 std::string target_dialect_c; |
| 407 std::string target_dialect_cc; |
| 408 std::string target_dialect_objc; |
| 409 std::string target_dialect_objcc; |
| 410 |
| 411 for (ConfigValuesIterator it(target); !it.done(); it.Next()) { |
| 412 target_includes.insert(target_includes.end(), |
| 413 it.cur().include_dirs().begin(), |
| 414 it.cur().include_dirs().end()); |
| 415 target_defines.insert(target_defines.end(), |
| 416 it.cur().defines().begin(), |
| 417 it.cur().defines().end()); |
| 418 |
| 419 ExtractDialect(target_dialect_c, it.cur().cflags_c(), false); |
| 420 ExtractDialect(target_dialect_c, it.cur().cflags(), false); |
| 421 ExtractDialect(target_dialect_cc, it.cur().cflags_cc(), true); |
| 422 ExtractDialect(target_dialect_cc, it.cur().cflags(), true); |
| 423 ExtractDialect(target_dialect_objc, it.cur().cflags_objc(), false); |
| 424 ExtractDialect(target_dialect_objc, it.cur().cflags(), false); |
| 425 ExtractDialect(target_dialect_objcc, it.cur().cflags_objcc(), true); |
| 426 ExtractDialect(target_dialect_objcc, it.cur().cflags(), true); |
| 427 } |
| 428 SortAndRemoveDuplicates(target_includes); |
| 429 SortAndRemoveDuplicates(target_defines); |
| 430 |
| 431 std::string target_cflags; |
| 432 |
| 433 target_includes = ExcludeSortedVectors(target_includes, common_includes); |
| 434 for (const auto& include : target_includes) { |
| 435 std::string rebased = include.is_system_absolute() |
| 436 ? include.value() |
| 437 : RebasePath(include.value(), root_build_dir); |
| 438 target_cflags += " -I"; |
| 439 target_cflags += rebased; |
| 440 } |
| 441 |
| 442 target_defines = ExcludeSortedVectors(target_defines, common_defines); |
| 443 for (const auto& define : target_defines) { |
| 444 target_cflags += " -D"; |
| 445 target_cflags += define; |
| 446 } |
| 447 |
| 448 if (!target_cflags.empty()) |
| 449 target_cflags = target_cflags.substr(1); |
| 450 |
| 451 for (const SourceFile& source : target->sources()) { |
| 452 std::string file_cflags = target_cflags; |
| 453 std::string file_dialect; |
| 454 const auto& ext = FindExtension(&source.value()); |
| 455 if (ext == "c") |
| 456 file_dialect = target_dialect_c; |
| 457 else if (ext == "cc" || ext == "cpp" || ext == "cxx") |
| 458 file_dialect = target_dialect_cc; |
| 459 else if (ext == "m") |
| 460 file_dialect = target_dialect_objc; |
| 461 else if (ext == "mm") |
| 462 file_dialect = target_dialect_objcc; |
| 463 |
| 464 if (!file_cflags.empty() && !file_dialect.empty()) |
| 465 file_cflags += " "; |
| 466 file_cflags += file_dialect; |
| 467 |
| 468 cflags[source] = file_cflags; |
| 469 } |
| 470 } |
| 471 |
| 472 attributes["USE_HEADERMAP"] = "NO"; |
| 473 |
| 474 if (!common_includes.empty()) { |
| 475 std::string includes; |
| 476 for (const auto& include : common_includes) { |
| 477 includes += include.is_system_absolute() |
| 478 ? include.value() |
| 479 : RebasePath(include.value(), root_build_dir); |
| 480 includes += "\n"; |
| 481 } |
| 482 attributes["HEADER_SEARCH_PATHS"] = includes; |
| 483 } |
| 484 |
| 485 if (!common_defines.empty()) { |
| 486 std::string defines; |
| 487 for (const auto& define : common_defines) { |
| 488 defines += define; |
| 489 defines += "\n"; |
| 490 } |
| 491 attributes["GCC_PREPROCESSOR_DEFINITIONS"] = defines; |
| 492 } |
| 493 } |
| 494 |
| 495 } // namespace |
| 496 |
| 319 void XcodeWriter::CreateSourcesProject( | 497 void XcodeWriter::CreateSourcesProject( |
| 320 const std::vector<const Target*>& targets, | 498 const std::vector<const Target*>& targets, |
| 321 const SourceDir& root_build_dir, | 499 const SourceDir& root_build_dir, |
| 322 const PBXAttributes& attributes, | 500 const PBXAttributes& attributes, |
| 323 const std::string& source_path, | 501 const std::string& source_path, |
| 324 const std::string& config_name, | 502 const std::string& config_name, |
| 325 TargetOsType target_os) { | 503 TargetOsType target_os) { |
| 504 |
| 326 std::vector<SourceFile> sources; | 505 std::vector<SourceFile> sources; |
| 506 std::vector<const Target*> indexed_targets; |
| 507 |
| 327 for (const Target* target : targets) { | 508 for (const Target* target : targets) { |
| 328 if (!target->settings()->is_default()) | 509 if (!target->settings()->is_default()) |
| 329 continue; | 510 continue; |
| 330 | 511 |
| 331 for (const SourceFile& source : target->sources()) { | 512 for (const SourceFile& source : target->sources()) { |
| 332 if (source.is_system_absolute()) | 513 if (source.is_system_absolute()) |
| 333 continue; | 514 continue; |
| 334 | 515 |
| 335 if (IsStringInOutputDir(root_build_dir, source.value())) | 516 if (IsStringInOutputDir(root_build_dir, source.value())) |
| 336 continue; | 517 continue; |
| 337 | 518 |
| 338 sources.push_back(source); | 519 sources.push_back(source); |
| 520 |
| 521 if (PBXProject::SourceFileShouldBeIndexed(source.value()) && |
| 522 (indexed_targets.empty() || indexed_targets.back() != target)) { |
| 523 indexed_targets.push_back(target); |
| 524 } |
| 339 } | 525 } |
| 340 } | 526 } |
| 341 | 527 |
| 528 std::map<SourceFile, std::string> cflags; |
| 529 PBXAttributes updated_attributes(attributes); |
| 530 PrepareBuildAttributes(indexed_targets, root_build_dir, cflags, |
| 531 updated_attributes); |
| 532 |
| 342 std::unique_ptr<PBXProject> sources_for_indexing( | 533 std::unique_ptr<PBXProject> sources_for_indexing( |
| 343 new PBXProject("sources", config_name, source_path, attributes)); | 534 new PBXProject("sources", config_name, source_path, updated_attributes)); |
| 344 | 535 |
| 345 // Sort sources to ensure determinisn of the project file generation and | 536 // Sort sources to ensure determinisn of the project file generation and |
| 346 // remove duplicate reference to the source files (can happen due to the | 537 // remove duplicate reference to the source files (can happen due to the |
| 347 // bundle_data targets). | 538 // bundle_data targets). |
| 348 std::sort(sources.begin(), sources.end()); | 539 SortAndRemoveDuplicates(sources); |
| 349 sources.erase(std::unique(sources.begin(), sources.end()), sources.end()); | |
| 350 | 540 |
| 351 SourceDir source_dir("//"); | 541 SourceDir source_dir("//"); |
| 352 for (const SourceFile& source : sources) { | 542 for (const SourceFile& source : sources) { |
| 353 std::string source_file = RebasePath(source.value(), source_dir); | 543 std::string source_file = RebasePath(source.value(), source_dir); |
| 354 sources_for_indexing->AddSourceFile(source_file); | 544 sources_for_indexing->AddSourceFile(source_file, cflags[source]); |
| 355 } | 545 } |
| 356 | 546 |
| 357 projects_.push_back(std::move(sources_for_indexing)); | 547 projects_.push_back(std::move(sources_for_indexing)); |
| 358 } | 548 } |
| 359 | 549 |
| 360 bool XcodeWriter::WriteFiles(const BuildSettings* build_settings, Err* err) { | 550 bool XcodeWriter::WriteFiles(const BuildSettings* build_settings, Err* err) { |
| 361 for (const auto& project : projects_) { | 551 for (const auto& project : projects_) { |
| 362 if (!WriteProjectFile(build_settings, project.get(), err)) | 552 if (!WriteProjectFile(build_settings, project.get(), err)) |
| 363 return false; | 553 return false; |
| 364 } | 554 } |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 425 for (const auto& object : pair.second) { | 615 for (const auto& object : pair.second) { |
| 426 object->Print(out, 2); | 616 object->Print(out, 2); |
| 427 } | 617 } |
| 428 out << "/* End " << ToString(pair.first) << " section */\n"; | 618 out << "/* End " << ToString(pair.first) << " section */\n"; |
| 429 } | 619 } |
| 430 | 620 |
| 431 out << "\t};\n" | 621 out << "\t};\n" |
| 432 << "\trootObject = " << project->Reference() << ";\n" | 622 << "\trootObject = " << project->Reference() << ";\n" |
| 433 << "}\n"; | 623 << "}\n"; |
| 434 } | 624 } |
| OLD | NEW |