| Index: tools/gn/xcode_writer.cc
|
| diff --git a/tools/gn/xcode_writer.cc b/tools/gn/xcode_writer.cc
|
| index 10624fa180d54a5d1df9067d8ca04ea720d5bb2d..09800a2dfb9735cf0dd2edde87783264f135c6d6 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"
|
| @@ -316,6 +317,183 @@ 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;
|
| +}
|
| +
|
| +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) {
|
| + std::vector<SourceDir> common_includes;
|
| + std::vector<std::string> common_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);
|
| + }
|
| + }
|
| +
|
| + for (const auto* target : indexed_targets) {
|
| + std::vector<SourceDir> target_includes;
|
| + std::vector<std::string> target_defines;
|
| +
|
| + 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());
|
| + target_defines.insert(target_defines.end(),
|
| + it.cur().defines().begin(),
|
| + it.cur().defines().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);
|
| + SortAndRemoveDuplicates(target_defines);
|
| +
|
| + std::string target_cflags;
|
| +
|
| + 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;
|
| + }
|
| +
|
| + target_defines = ExcludeSortedVectors(target_defines, common_defines);
|
| + for (const auto& define : target_defines) {
|
| + target_cflags += " -D";
|
| + target_cflags += define;
|
| + }
|
| +
|
| + if (!target_cflags.empty())
|
| + target_cflags = target_cflags.substr(1);
|
| +
|
| + 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;
|
| + }
|
| + }
|
| +
|
| + attributes["USE_HEADERMAP"] = "NO";
|
| +
|
| + if (!common_includes.empty()) {
|
| + std::string includes;
|
| + for (const auto& include : common_includes) {
|
| + includes += include.is_system_absolute()
|
| + ? include.value()
|
| + : RebasePath(include.value(), root_build_dir);
|
| + includes += "\n";
|
| + }
|
| + attributes["HEADER_SEARCH_PATHS"] = includes;
|
| + }
|
| +
|
| + if (!common_defines.empty()) {
|
| + std::string defines;
|
| + for (const auto& define : common_defines) {
|
| + defines += define;
|
| + defines += "\n";
|
| + }
|
| + attributes["GCC_PREPROCESSOR_DEFINITIONS"] = defines;
|
| + }
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| void XcodeWriter::CreateSourcesProject(
|
| const std::vector<const Target*>& targets,
|
| const SourceDir& root_build_dir,
|
| @@ -323,7 +501,10 @@ void XcodeWriter::CreateSourcesProject(
|
| const std::string& source_path,
|
| 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 +517,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));
|
|
|