Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(418)

Side by Side Diff: tools/gn/xcode_writer.cc

Issue 2057873002: [GN] Export include directories, defines and dialects to Xcode projects Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Remove preprocessor defines on individual files Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « tools/gn/xcode_writer.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
146 const std::string& dir_filters_string, 147 const std::string& dir_filters_string,
147 const BuildSettings* build_settings, 148 const BuildSettings* build_settings,
148 Builder* builder, 149 Builder* builder,
149 Err* err) { 150 Err* err) {
150 const XcodeWriter::TargetOsType target_os = 151 const XcodeWriter::TargetOsType target_os =
151 GetTargetOs(build_settings->build_args()); 152 GetTargetOs(build_settings->build_args());
152 153
153 PBXAttributes attributes; 154 PBXAttributes attributes;
154 switch (target_os) { 155 switch (target_os) {
155 case XcodeWriter::WRITER_TARGET_OS_IOS: 156 case XcodeWriter::WRITER_TARGET_OS_IOS:
156 attributes["SDKROOT"] = "iphoneos"; 157 attributes.insert(std::make_pair("SDKROOT", "iphoneos"));
157 attributes["TARGETED_DEVICE_FAMILY"] = "1,2"; 158 attributes.insert(std::make_pair("TARGETED_DEVICE_FAMILY", "1,2"));
158 break; 159 break;
159 case XcodeWriter::WRITER_TARGET_OS_MACOS: 160 case XcodeWriter::WRITER_TARGET_OS_MACOS:
160 attributes["ARCHS"] = GetArchs(build_settings->build_args()); 161 attributes.insert(std::make_pair("SDKROOT", "macosx10.11"));
161 attributes["SDKROOT"] = "macosx10.11"; 162 attributes.insert(
163 std::make_pair("ARCHS", GetArchs(build_settings->build_args())));
162 break; 164 break;
163 } 165 }
164 166
165 const std::string source_path = 167 const std::string source_path =
166 base::FilePath::FromUTF8Unsafe( 168 base::FilePath::FromUTF8Unsafe(
167 RebasePath("//", build_settings->build_dir())) 169 RebasePath("//", build_settings->build_dir()))
168 .StripTrailingSeparators() 170 .StripTrailingSeparators()
169 .AsUTF8Unsafe(); 171 .AsUTF8Unsafe();
170 172
171 std::string config_name = build_settings->build_dir() 173 std::string config_name = build_settings->build_dir()
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after
309 break; 311 break;
310 312
311 default: 313 default:
312 break; 314 break;
313 } 315 }
314 } 316 }
315 317
316 projects_.push_back(std::move(main_project)); 318 projects_.push_back(std::move(main_project));
317 } 319 }
318 320
321 namespace {
322
323 template <typename T>
324 void SortAndRemoveDuplicates(std::vector<T>& vec) {
325 std::sort(vec.begin(), vec.end());
326 vec.erase(std::unique(vec.begin(), vec.end()), vec.end());
327 }
328
329 template <typename T>
330 std::vector<T> IntersectSortedVectors(const std::vector<T>& vec,
331 const std::vector<T>& vec2) {
332 std::vector<T> intersection;
333 std::set_intersection(vec.begin(), vec.end(), vec2.begin(), vec2.end(),
334 std::back_inserter(intersection));
335 return intersection;
336 }
337
338 template <typename T>
339 std::vector<T> ExcludeSortedVectors(const std::vector<T>& from,
340 const std::vector<T>& what) {
341 std::vector<T> difference;
342 std::set_difference(from.begin(), from.end(), what.begin(), what.end(),
343 std::back_inserter(difference));
344 return difference;
345 }
346
347 // Extracts dialect from flags, will not replace altrady extracted value
348 void ExtractDialect(std::string& res,
349 const std::vector<std::string>& flags,
350 bool cc) {
351 for (const auto& flag : flags) {
352 if (res.empty() && flag.compare(0, 5, "-std=") == 0) {
353 res = flag;
354 }
355 if (!res.empty()) {
356 break;
357 }
358 }
359
360 // we're looking for c++ dialect, it must have + in name
361 if (cc && res.find('+') == std::string::npos)
362 res.clear();
363
364 // we're looking for c dialect, it must not have + in name
365 if (!cc && res.find('+') != std::string::npos)
366 res.clear();
367 }
368
369 void PrepareBuildAttributes(const std::vector<const Target*>& indexed_targets,
370 const SourceDir& root_build_dir,
371 std::map<SourceFile, std::string>& cflags,
372 PBXAttributes& attributes) {
373 // these will be specified at xcode target level and apply to all files
374 std::vector<SourceDir> common_includes;
375 std::vector<std::string> common_defines;
376
377 // gather common includes and defines
378 for (const auto* target : indexed_targets) {
379 std::vector<SourceDir> target_includes;
380 std::vector<std::string> target_defines;
381
382 for (ConfigValuesIterator it(target); !it.done(); it.Next()) {
383 target_includes.insert(target_includes.end(),
384 it.cur().include_dirs().begin(),
385 it.cur().include_dirs().end());
386 target_defines.insert(target_defines.end(), it.cur().defines().begin(),
387 it.cur().defines().end());
388 }
389 SortAndRemoveDuplicates(target_includes);
390 SortAndRemoveDuplicates(target_defines);
391
392 if (target == indexed_targets.front()) {
393 common_includes = std::move(target_includes);
394 common_defines = std::move(target_defines);
395 } else {
396 if (common_includes.empty() && common_defines.empty())
397 break;
398 common_includes =
399 IntersectSortedVectors(common_includes, target_includes);
400 common_defines = IntersectSortedVectors(common_defines, target_defines);
401 }
402 }
403
404 // gather specific cflags for individual files
405 for (const auto* target : indexed_targets) {
406 // only add taget includes to specific files; ignore target specific defines
407 // because they prevent using precompiled headers during indexing
408 std::vector<SourceDir> target_includes;
409
410 std::string target_dialect_c;
411 std::string target_dialect_cc;
412 std::string target_dialect_objc;
413 std::string target_dialect_objcc;
414
415 for (ConfigValuesIterator it(target); !it.done(); it.Next()) {
416 target_includes.insert(target_includes.end(),
417 it.cur().include_dirs().begin(),
418 it.cur().include_dirs().end());
419
420 ExtractDialect(target_dialect_c, it.cur().cflags_c(), false);
421 ExtractDialect(target_dialect_c, it.cur().cflags(), false);
422 ExtractDialect(target_dialect_cc, it.cur().cflags_cc(), true);
423 ExtractDialect(target_dialect_cc, it.cur().cflags(), true);
424 ExtractDialect(target_dialect_objc, it.cur().cflags_objc(), false);
425 ExtractDialect(target_dialect_objc, it.cur().cflags(), false);
426 ExtractDialect(target_dialect_objcc, it.cur().cflags_objcc(), true);
427 ExtractDialect(target_dialect_objcc, it.cur().cflags(), true);
428 }
429 SortAndRemoveDuplicates(target_includes);
430
431 std::string target_cflags;
432
433 // includes specific for this target
434 target_includes = ExcludeSortedVectors(target_includes, common_includes);
435 for (const auto& include : target_includes) {
436 std::string rebased = include.is_system_absolute()
437 ? include.value()
438 : RebasePath(include.value(), root_build_dir);
439 target_cflags += " -I";
440 target_cflags += rebased;
441 }
442
443 if (!target_cflags.empty()) // remove leading space
444 target_cflags = target_cflags.substr(1);
445
446 // for each file set target specific cflags and language dialect
447 // according to file type
448 for (const SourceFile& source : target->sources()) {
449 std::string file_cflags = target_cflags;
450 std::string file_dialect;
451 const auto& ext = FindExtension(&source.value());
452 if (ext == "c")
453 file_dialect = target_dialect_c;
454 else if (ext == "cc" || ext == "cpp" || ext == "cxx")
455 file_dialect = target_dialect_cc;
456 else if (ext == "m")
457 file_dialect = target_dialect_objc;
458 else if (ext == "mm")
459 file_dialect = target_dialect_objcc;
460
461 if (!file_cflags.empty() && !file_dialect.empty())
462 file_cflags += " ";
463 file_cflags += file_dialect;
464
465 cflags[source] = file_cflags;
466 }
467 }
468
469 // HEADERMAP breaks indexing if there are multiple files with same name
470 // in different folders; It also means that header lookup during indexing
471 // works differently than during build, which is not desired
472 attributes.erase("USE_HEADERMAP");
473 attributes.insert(std::make_pair("USE_HEADERMAP", "NO"));
474
475 if (!common_includes.empty()) {
476 for (const auto& include : common_includes) {
477 std::string rebased = include.is_system_absolute()
478 ? include.value()
479 : RebasePath(include.value(), root_build_dir);
480 attributes.insert(std::make_pair("HEADER_SEARCH_PATHS", rebased));
481 }
482 }
483
484 if (!common_defines.empty()) {
485 for (const auto& define : common_defines) {
486 attributes.insert(std::make_pair("GCC_PREPROCESSOR_DEFINITIONS", define));
487 }
488 }
489 }
490
491 } // namespace
492
319 void XcodeWriter::CreateSourcesProject( 493 void XcodeWriter::CreateSourcesProject(
320 const std::vector<const Target*>& targets, 494 const std::vector<const Target*>& targets,
321 const SourceDir& root_build_dir, 495 const SourceDir& root_build_dir,
322 const PBXAttributes& attributes, 496 const PBXAttributes& attributes,
323 const std::string& source_path, 497 const std::string& source_path,
324 const std::string& config_name, 498 const std::string& config_name,
325 TargetOsType target_os) { 499 TargetOsType target_os) {
326 std::vector<SourceFile> sources; 500 std::vector<SourceFile> sources;
501 std::vector<const Target*> indexed_targets;
502
327 for (const Target* target : targets) { 503 for (const Target* target : targets) {
328 if (!target->settings()->is_default()) 504 if (!target->settings()->is_default())
329 continue; 505 continue;
330 506
331 for (const SourceFile& source : target->sources()) { 507 for (const SourceFile& source : target->sources()) {
332 if (source.is_system_absolute()) 508 if (source.is_system_absolute())
333 continue; 509 continue;
334 510
335 if (IsStringInOutputDir(root_build_dir, source.value())) 511 if (IsStringInOutputDir(root_build_dir, source.value()))
336 continue; 512 continue;
337 513
338 sources.push_back(source); 514 sources.push_back(source);
515
516 if (PBXProject::SourceFileShouldBeIndexed(source.value()) &&
517 (indexed_targets.empty() || indexed_targets.back() != target)) {
518 indexed_targets.push_back(target);
519 }
339 } 520 }
340 } 521 }
341 522
523 std::map<SourceFile, std::string> cflags;
524 PBXAttributes updated_attributes(attributes);
525 PrepareBuildAttributes(indexed_targets, root_build_dir, cflags,
526 updated_attributes);
527
342 std::unique_ptr<PBXProject> sources_for_indexing( 528 std::unique_ptr<PBXProject> sources_for_indexing(
343 new PBXProject("sources", config_name, source_path, attributes)); 529 new PBXProject("sources", config_name, source_path, updated_attributes));
344 530
345 // Sort sources to ensure determinisn of the project file generation and 531 // Sort sources to ensure determinisn of the project file generation and
346 // remove duplicate reference to the source files (can happen due to the 532 // remove duplicate reference to the source files (can happen due to the
347 // bundle_data targets). 533 // bundle_data targets).
348 std::sort(sources.begin(), sources.end()); 534 SortAndRemoveDuplicates(sources);
349 sources.erase(std::unique(sources.begin(), sources.end()), sources.end());
350 535
351 SourceDir source_dir("//"); 536 SourceDir source_dir("//");
352 for (const SourceFile& source : sources) { 537 for (const SourceFile& source : sources) {
353 std::string source_file = RebasePath(source.value(), source_dir); 538 std::string source_file = RebasePath(source.value(), source_dir);
354 sources_for_indexing->AddSourceFile(source_file); 539 sources_for_indexing->AddSourceFile(source_file, cflags[source]);
355 } 540 }
356 541
357 projects_.push_back(std::move(sources_for_indexing)); 542 projects_.push_back(std::move(sources_for_indexing));
358 } 543 }
359 544
360 bool XcodeWriter::WriteFiles(const BuildSettings* build_settings, Err* err) { 545 bool XcodeWriter::WriteFiles(const BuildSettings* build_settings, Err* err) {
361 for (const auto& project : projects_) { 546 for (const auto& project : projects_) {
362 if (!WriteProjectFile(build_settings, project.get(), err)) 547 if (!WriteProjectFile(build_settings, project.get(), err))
363 return false; 548 return false;
364 } 549 }
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
425 for (const auto& object : pair.second) { 610 for (const auto& object : pair.second) {
426 object->Print(out, 2); 611 object->Print(out, 2);
427 } 612 }
428 out << "/* End " << ToString(pair.first) << " section */\n"; 613 out << "/* End " << ToString(pair.first) << " section */\n";
429 } 614 }
430 615
431 out << "\t};\n" 616 out << "\t};\n"
432 << "\trootObject = " << project->Reference() << ";\n" 617 << "\trootObject = " << project->Reference() << ";\n"
433 << "}\n"; 618 << "}\n";
434 } 619 }
OLDNEW
« no previous file with comments | « tools/gn/xcode_writer.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698