| Index: tools/gn/xcode_writer.cc
|
| diff --git a/tools/gn/xcode_writer.cc b/tools/gn/xcode_writer.cc
|
| index 10624fa180d54a5d1df9067d8ca04ea720d5bb2d..e2f10b0ba6d7ef65e54341ad9afa1ebe84bccd21 100644
|
| --- a/tools/gn/xcode_writer.cc
|
| +++ b/tools/gn/xcode_writer.cc
|
| @@ -20,6 +20,7 @@
|
| #include "tools/gn/build_settings.h"
|
| #include "tools/gn/builder.h"
|
| #include "tools/gn/commands.h"
|
| +#include "tools/gn/config_values_extractors.h"
|
| #include "tools/gn/deps_iterator.h"
|
| #include "tools/gn/filesystem_utils.h"
|
| #include "tools/gn/settings.h"
|
| @@ -153,12 +154,13 @@ bool XcodeWriter::RunAndWriteFiles(const std::string& workspace_name,
|
| PBXAttributes attributes;
|
| switch (target_os) {
|
| case XcodeWriter::WRITER_TARGET_OS_IOS:
|
| - attributes["SDKROOT"] = "iphoneos";
|
| - attributes["TARGETED_DEVICE_FAMILY"] = "1,2";
|
| + attributes.insert(std::make_pair("SDKROOT", "iphoneos"));
|
| + attributes.insert(std::make_pair("TARGETED_DEVICE_FAMILY", "1,2"));
|
| break;
|
| case XcodeWriter::WRITER_TARGET_OS_MACOS:
|
| - attributes["ARCHS"] = GetArchs(build_settings->build_args());
|
| - attributes["SDKROOT"] = "macosx10.11";
|
| + attributes.insert(std::make_pair("SDKROOT", "macosx10.11"));
|
| + attributes.insert(
|
| + std::make_pair("ARCHS", GetArchs(build_settings->build_args())));
|
| break;
|
| }
|
|
|
| @@ -316,6 +318,178 @@ void XcodeWriter::CreateProductsProject(
|
| projects_.push_back(std::move(main_project));
|
| }
|
|
|
| +namespace {
|
| +
|
| +template <typename T>
|
| +void SortAndRemoveDuplicates(std::vector<T>& vec) {
|
| + std::sort(vec.begin(), vec.end());
|
| + vec.erase(std::unique(vec.begin(), vec.end()), vec.end());
|
| +}
|
| +
|
| +template <typename T>
|
| +std::vector<T> IntersectSortedVectors(const std::vector<T>& vec,
|
| + const std::vector<T>& vec2) {
|
| + std::vector<T> intersection;
|
| + std::set_intersection(vec.begin(), vec.end(), vec2.begin(), vec2.end(),
|
| + std::back_inserter(intersection));
|
| + return intersection;
|
| +}
|
| +
|
| +template <typename T>
|
| +std::vector<T> ExcludeSortedVectors(const std::vector<T>& from,
|
| + const std::vector<T>& what) {
|
| + std::vector<T> difference;
|
| + std::set_difference(from.begin(), from.end(), what.begin(), what.end(),
|
| + std::back_inserter(difference));
|
| + return difference;
|
| +}
|
| +
|
| +// Extracts dialect from flags, will not replace altrady extracted value
|
| +void ExtractDialect(std::string& res,
|
| + const std::vector<std::string>& flags,
|
| + bool cc) {
|
| + for (const auto& flag : flags) {
|
| + if (res.empty() && flag.compare(0, 5, "-std=") == 0) {
|
| + res = flag;
|
| + }
|
| + if (!res.empty()) {
|
| + break;
|
| + }
|
| + }
|
| +
|
| + // we're looking for c++ dialect, it must have + in name
|
| + if (cc && res.find('+') == std::string::npos)
|
| + res.clear();
|
| +
|
| + // we're looking for c dialect, it must not have + in name
|
| + if (!cc && res.find('+') != std::string::npos)
|
| + res.clear();
|
| +}
|
| +
|
| +void PrepareBuildAttributes(const std::vector<const Target*>& indexed_targets,
|
| + const SourceDir& root_build_dir,
|
| + std::map<SourceFile, std::string>& cflags,
|
| + PBXAttributes& attributes) {
|
| + // these will be specified at xcode target level and apply to all files
|
| + std::vector<SourceDir> common_includes;
|
| + std::vector<std::string> common_defines;
|
| +
|
| + // gather common includes and defines
|
| + for (const auto* target : indexed_targets) {
|
| + std::vector<SourceDir> target_includes;
|
| + std::vector<std::string> target_defines;
|
| +
|
| + for (ConfigValuesIterator it(target); !it.done(); it.Next()) {
|
| + target_includes.insert(target_includes.end(),
|
| + it.cur().include_dirs().begin(),
|
| + it.cur().include_dirs().end());
|
| + target_defines.insert(target_defines.end(), it.cur().defines().begin(),
|
| + it.cur().defines().end());
|
| + }
|
| + SortAndRemoveDuplicates(target_includes);
|
| + SortAndRemoveDuplicates(target_defines);
|
| +
|
| + if (target == indexed_targets.front()) {
|
| + common_includes = std::move(target_includes);
|
| + common_defines = std::move(target_defines);
|
| + } else {
|
| + if (common_includes.empty() && common_defines.empty())
|
| + break;
|
| + common_includes =
|
| + IntersectSortedVectors(common_includes, target_includes);
|
| + common_defines = IntersectSortedVectors(common_defines, target_defines);
|
| + }
|
| + }
|
| +
|
| + // gather specific cflags for individual files
|
| + for (const auto* target : indexed_targets) {
|
| + // only add taget includes to specific files; ignore target specific defines
|
| + // because they prevent using precompiled headers during indexing
|
| + std::vector<SourceDir> target_includes;
|
| +
|
| + std::string target_dialect_c;
|
| + std::string target_dialect_cc;
|
| + std::string target_dialect_objc;
|
| + std::string target_dialect_objcc;
|
| +
|
| + for (ConfigValuesIterator it(target); !it.done(); it.Next()) {
|
| + target_includes.insert(target_includes.end(),
|
| + it.cur().include_dirs().begin(),
|
| + it.cur().include_dirs().end());
|
| +
|
| + ExtractDialect(target_dialect_c, it.cur().cflags_c(), false);
|
| + ExtractDialect(target_dialect_c, it.cur().cflags(), false);
|
| + ExtractDialect(target_dialect_cc, it.cur().cflags_cc(), true);
|
| + ExtractDialect(target_dialect_cc, it.cur().cflags(), true);
|
| + ExtractDialect(target_dialect_objc, it.cur().cflags_objc(), false);
|
| + ExtractDialect(target_dialect_objc, it.cur().cflags(), false);
|
| + ExtractDialect(target_dialect_objcc, it.cur().cflags_objcc(), true);
|
| + ExtractDialect(target_dialect_objcc, it.cur().cflags(), true);
|
| + }
|
| + SortAndRemoveDuplicates(target_includes);
|
| +
|
| + std::string target_cflags;
|
| +
|
| + // includes specific for this target
|
| + target_includes = ExcludeSortedVectors(target_includes, common_includes);
|
| + for (const auto& include : target_includes) {
|
| + std::string rebased = include.is_system_absolute()
|
| + ? include.value()
|
| + : RebasePath(include.value(), root_build_dir);
|
| + target_cflags += " -I";
|
| + target_cflags += rebased;
|
| + }
|
| +
|
| + if (!target_cflags.empty()) // remove leading space
|
| + target_cflags = target_cflags.substr(1);
|
| +
|
| + // for each file set target specific cflags and language dialect
|
| + // according to file type
|
| + for (const SourceFile& source : target->sources()) {
|
| + std::string file_cflags = target_cflags;
|
| + std::string file_dialect;
|
| + const auto& ext = FindExtension(&source.value());
|
| + if (ext == "c")
|
| + file_dialect = target_dialect_c;
|
| + else if (ext == "cc" || ext == "cpp" || ext == "cxx")
|
| + file_dialect = target_dialect_cc;
|
| + else if (ext == "m")
|
| + file_dialect = target_dialect_objc;
|
| + else if (ext == "mm")
|
| + file_dialect = target_dialect_objcc;
|
| +
|
| + if (!file_cflags.empty() && !file_dialect.empty())
|
| + file_cflags += " ";
|
| + file_cflags += file_dialect;
|
| +
|
| + cflags[source] = file_cflags;
|
| + }
|
| + }
|
| +
|
| + // HEADERMAP breaks indexing if there are multiple files with same name
|
| + // in different folders; It also means that header lookup during indexing
|
| + // works differently than during build, which is not desired
|
| + attributes.erase("USE_HEADERMAP");
|
| + attributes.insert(std::make_pair("USE_HEADERMAP", "NO"));
|
| +
|
| + if (!common_includes.empty()) {
|
| + for (const auto& include : common_includes) {
|
| + std::string rebased = include.is_system_absolute()
|
| + ? include.value()
|
| + : RebasePath(include.value(), root_build_dir);
|
| + attributes.insert(std::make_pair("HEADER_SEARCH_PATHS", rebased));
|
| + }
|
| + }
|
| +
|
| + if (!common_defines.empty()) {
|
| + for (const auto& define : common_defines) {
|
| + attributes.insert(std::make_pair("GCC_PREPROCESSOR_DEFINITIONS", define));
|
| + }
|
| + }
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| void XcodeWriter::CreateSourcesProject(
|
| const std::vector<const Target*>& targets,
|
| const SourceDir& root_build_dir,
|
| @@ -324,6 +498,8 @@ void XcodeWriter::CreateSourcesProject(
|
| const std::string& config_name,
|
| TargetOsType target_os) {
|
| std::vector<SourceFile> sources;
|
| + std::vector<const Target*> indexed_targets;
|
| +
|
| for (const Target* target : targets) {
|
| if (!target->settings()->is_default())
|
| continue;
|
| @@ -336,22 +512,31 @@ void XcodeWriter::CreateSourcesProject(
|
| continue;
|
|
|
| sources.push_back(source);
|
| +
|
| + if (PBXProject::SourceFileShouldBeIndexed(source.value()) &&
|
| + (indexed_targets.empty() || indexed_targets.back() != target)) {
|
| + indexed_targets.push_back(target);
|
| + }
|
| }
|
| }
|
|
|
| + std::map<SourceFile, std::string> cflags;
|
| + PBXAttributes updated_attributes(attributes);
|
| + PrepareBuildAttributes(indexed_targets, root_build_dir, cflags,
|
| + updated_attributes);
|
| +
|
| std::unique_ptr<PBXProject> sources_for_indexing(
|
| - new PBXProject("sources", config_name, source_path, attributes));
|
| + new PBXProject("sources", config_name, source_path, updated_attributes));
|
|
|
| // Sort sources to ensure determinisn of the project file generation and
|
| // remove duplicate reference to the source files (can happen due to the
|
| // bundle_data targets).
|
| - std::sort(sources.begin(), sources.end());
|
| - sources.erase(std::unique(sources.begin(), sources.end()), sources.end());
|
| + SortAndRemoveDuplicates(sources);
|
|
|
| SourceDir source_dir("//");
|
| for (const SourceFile& source : sources) {
|
| std::string source_file = RebasePath(source.value(), source_dir);
|
| - sources_for_indexing->AddSourceFile(source_file);
|
| + sources_for_indexing->AddSourceFile(source_file, cflags[source]);
|
| }
|
|
|
| projects_.push_back(std::move(sources_for_indexing));
|
|
|