Skip duplicated items when generating build command For some of the compiler settings, duplicate items can be omitted (e.g. include_dirs, frameworks, libs, ...). The order of the item is important, so changing the storage to std::set<T> would not work (and this would break with recursion anyway). Instead add support to the code generating to compiler command-line to skip over duplicated item when it make sense. Bug: none Change-Id: I9096a3a804b5e9a3673c32f816b0e189eda4de84 Reviewed-on: https://gn-review.googlesource.com/c/gn/+/11701 Commit-Queue: Sylvain Defresne <sdefresne@chromium.org> Reviewed-by: Brett Wilson <brettw@chromium.org>
diff --git a/src/gn/compile_commands_writer.cc b/src/gn/compile_commands_writer.cc index 1d9d5b4..74f6990 100644 --- a/src/gn/compile_commands_writer.cc +++ b/src/gn/compile_commands_writer.cc
@@ -57,12 +57,13 @@ // NOTE: The Windows compiler cannot properly deduce the first parameter type // so pass it at each call site to ensure proper builds for this platform. template <typename T, typename Writer> -std::string FlagsGetter(const Target* target, +std::string FlagsGetter(RecursiveWriterConfig config, + const Target* target, const std::vector<T>& (ConfigValues::*getter)() const, const Writer& writer) { std::string result; std::ostringstream out; - RecursiveTargetConfigToStream<T>(target, getter, writer, out); + RecursiveTargetConfigToStream<T>(config, target, getter, writer, out); base::EscapeJSONString(out.str(), false, &result); return result; }; @@ -74,54 +75,60 @@ bool has_precompiled_headers = target->config_values().has_precompiled_headers(); - flags.defines = - FlagsGetter<std::string>(target, &ConfigValues::defines, - DefineWriter(ESCAPE_COMPILATION_DATABASE)); + flags.defines = FlagsGetter<std::string>( + kRecursiveWriterSkipDuplicates, target, &ConfigValues::defines, + DefineWriter(ESCAPE_COMPILATION_DATABASE)); - flags.framework_dirs = - FlagsGetter<SourceDir>(target, &ConfigValues::framework_dirs, - FrameworkDirsWriter(path_output, "-F")); + flags.framework_dirs = FlagsGetter<SourceDir>( + kRecursiveWriterSkipDuplicates, target, &ConfigValues::framework_dirs, + FrameworkDirsWriter(path_output, "-F")); flags.frameworks = FlagsGetter<std::string>( - target, &ConfigValues::frameworks, + kRecursiveWriterSkipDuplicates, target, &ConfigValues::frameworks, FrameworksWriter(ESCAPE_COMPILATION_DATABASE, "-framework")); flags.frameworks += FlagsGetter<std::string>( - target, &ConfigValues::weak_frameworks, + kRecursiveWriterSkipDuplicates, target, &ConfigValues::weak_frameworks, FrameworksWriter(ESCAPE_COMPILATION_DATABASE, "-weak_framework")); - flags.includes = FlagsGetter<SourceDir>(target, &ConfigValues::include_dirs, + flags.includes = FlagsGetter<SourceDir>(kRecursiveWriterSkipDuplicates, + target, &ConfigValues::include_dirs, IncludeWriter(path_output)); // Helper lambda to call WriteOneFlag() and return the resulting // escaped JSON string. - auto one_flag = [&](const Substitution* substitution, + auto one_flag = [&](RecursiveWriterConfig config, + const Substitution* substitution, bool has_precompiled_headers, const char* tool_name, const std::vector<std::string>& (ConfigValues::*getter)() const) -> std::string { std::string result; std::ostringstream out; - WriteOneFlag(target, substitution, has_precompiled_headers, tool_name, - getter, opts, path_output, out, /*write_substitution=*/false); + WriteOneFlag(config, target, substitution, has_precompiled_headers, + tool_name, getter, opts, path_output, out, + /*write_substitution=*/false); base::EscapeJSONString(out.str(), false, &result); return result; }; - flags.cflags = one_flag(&CSubstitutionCFlags, false, Tool::kToolNone, - &ConfigValues::cflags); + flags.cflags = one_flag(kRecursiveWriterKeepDuplicates, &CSubstitutionCFlags, + false, Tool::kToolNone, &ConfigValues::cflags); - flags.cflags_c = one_flag(&CSubstitutionCFlagsC, has_precompiled_headers, + flags.cflags_c = one_flag(kRecursiveWriterKeepDuplicates, + &CSubstitutionCFlagsC, has_precompiled_headers, CTool::kCToolCc, &ConfigValues::cflags_c); - flags.cflags_cc = one_flag(&CSubstitutionCFlagsCc, has_precompiled_headers, + flags.cflags_cc = one_flag(kRecursiveWriterKeepDuplicates, + &CSubstitutionCFlagsCc, has_precompiled_headers, CTool::kCToolCxx, &ConfigValues::cflags_cc); - flags.cflags_objc = - one_flag(&CSubstitutionCFlagsObjC, has_precompiled_headers, - CTool::kCToolObjC, &ConfigValues::cflags_objc); + flags.cflags_objc = one_flag( + kRecursiveWriterKeepDuplicates, &CSubstitutionCFlagsObjC, + has_precompiled_headers, CTool::kCToolObjC, &ConfigValues::cflags_objc); flags.cflags_objcc = - one_flag(&CSubstitutionCFlagsObjCc, has_precompiled_headers, - CTool::kCToolObjCxx, &ConfigValues::cflags_objcc); + one_flag(kRecursiveWriterKeepDuplicates, &CSubstitutionCFlagsObjCc, + has_precompiled_headers, CTool::kCToolObjCxx, + &ConfigValues::cflags_objcc); } void WriteFile(const SourceFile& source,
diff --git a/src/gn/config_values_extractors.cc b/src/gn/config_values_extractors.cc index 409e11d..a369008 100644 --- a/src/gn/config_values_extractors.cc +++ b/src/gn/config_values_extractors.cc
@@ -25,10 +25,11 @@ } // namespace void RecursiveTargetConfigStringsToStream( + RecursiveWriterConfig config, const Target* target, const std::vector<std::string>& (ConfigValues::*getter)() const, const EscapeOptions& escape_options, std::ostream& out) { - RecursiveTargetConfigToStream(target, getter, + RecursiveTargetConfigToStream(config, target, getter, EscapedStringWriter(escape_options), out); }
diff --git a/src/gn/config_values_extractors.h b/src/gn/config_values_extractors.h index ae51761..6479f21 100644 --- a/src/gn/config_values_extractors.h +++ b/src/gn/config_values_extractors.h
@@ -68,32 +68,43 @@ int cur_index_ = -1; }; -template <typename T, class Writer> -inline void ConfigValuesToStream(const ConfigValues& values, - const std::vector<T>& (ConfigValues::*getter)() - const, - const Writer& writer, - std::ostream& out) { - const std::vector<T>& v = (values.*getter)(); - for (size_t i = 0; i < v.size(); i++) - writer(v[i], out); -} +enum RecursiveWriterConfig { + kRecursiveWriterKeepDuplicates, + kRecursiveWriterSkipDuplicates, +}; // Writes a given config value that applies to a given target. This collects // all values from the target itself and all configs that apply, and writes // then in order. template <typename T, class Writer> inline void RecursiveTargetConfigToStream( + RecursiveWriterConfig config, const Target* target, const std::vector<T>& (ConfigValues::*getter)() const, const Writer& writer, std::ostream& out) { - for (ConfigValuesIterator iter(target); !iter.done(); iter.Next()) - ConfigValuesToStream(iter.cur(), getter, writer, out); + std::set<T> seen; + for (ConfigValuesIterator iter(target); !iter.done(); iter.Next()) { + const std::vector<T>& values = ((iter.cur()).*getter)(); + for (size_t i = 0; i < values.size(); i++) { + switch (config) { + case kRecursiveWriterKeepDuplicates: + writer(values[i], out); + break; + + case kRecursiveWriterSkipDuplicates: + if (seen.find(values[i]) == seen.end()) { + seen.insert(values[i]); + writer(values[i], out); + } + } + } + } } // Writes the values out as strings with no transformation. void RecursiveTargetConfigStringsToStream( + RecursiveWriterConfig config, const Target* target, const std::vector<std::string>& (ConfigValues::*getter)() const, const EscapeOptions& escape_options,
diff --git a/src/gn/config_values_extractors_unittest.cc b/src/gn/config_values_extractors_unittest.cc index 7c520ad..860d87c 100644 --- a/src/gn/config_values_extractors_unittest.cc +++ b/src/gn/config_values_extractors_unittest.cc
@@ -37,6 +37,8 @@ // Set up dep2, direct and all dependent configs. Config dep2_all(setup.settings(), Label(SourceDir("//dep2/"), "all")); dep2_all.own_values().cflags().push_back("--dep2-all"); + dep2_all.own_values().cflags().push_back("--dep2-all"); + dep2_all.own_values().include_dirs().push_back(SourceDir("//dep2/all/")); dep2_all.own_values().include_dirs().push_back(SourceDir("//dep2/all/")); ASSERT_TRUE(dep2_all.OnResolved(&err)); @@ -124,16 +126,18 @@ std::ostringstream flag_out; FlagWriter flag_writer; RecursiveTargetConfigToStream<std::string, FlagWriter>( - &target, &ConfigValues::cflags, flag_writer, flag_out); + kRecursiveWriterKeepDuplicates, &target, &ConfigValues::cflags, + flag_writer, flag_out); EXPECT_EQ(flag_out.str(), "--target --target-config --target-all --target-direct " - "--dep1-all --dep1-all-sub --dep2-all --dep1-direct "); + "--dep1-all --dep1-all-sub --dep2-all --dep2-all --dep1-direct "); // Verify include dirs by serializing. std::ostringstream include_out; IncludeWriter include_writer; RecursiveTargetConfigToStream<SourceDir, IncludeWriter>( - &target, &ConfigValues::include_dirs, include_writer, include_out); + kRecursiveWriterSkipDuplicates, &target, &ConfigValues::include_dirs, + include_writer, include_out); EXPECT_EQ(include_out.str(), "//target/ //target/config/ //target/all/ //target/direct/ " "//dep1/all/ //dep2/all/ //dep1/direct/ ");
diff --git a/src/gn/desc_builder.cc b/src/gn/desc_builder.cc index bbbf831..325735a 100644 --- a/src/gn/desc_builder.cc +++ b/src/gn/desc_builder.cc
@@ -491,26 +491,39 @@ FillInBundle(res.get()); if (is_binary_output) { -#define CONFIG_VALUE_ARRAY_HANDLER(name, type) \ - if (what(#name)) { \ - ValuePtr ptr = RenderConfigValues<type>(&ConfigValues::name); \ - if (ptr) { \ - res->SetWithoutPathExpansion(#name, std::move(ptr)); \ - } \ +#define CONFIG_VALUE_ARRAY_HANDLER(name, type, config) \ + if (what(#name)) { \ + ValuePtr ptr = RenderConfigValues<type>(config, &ConfigValues::name); \ + if (ptr) { \ + res->SetWithoutPathExpansion(#name, std::move(ptr)); \ + } \ } - CONFIG_VALUE_ARRAY_HANDLER(arflags, std::string) - CONFIG_VALUE_ARRAY_HANDLER(asmflags, std::string) - CONFIG_VALUE_ARRAY_HANDLER(cflags, std::string) - CONFIG_VALUE_ARRAY_HANDLER(cflags_c, std::string) - CONFIG_VALUE_ARRAY_HANDLER(cflags_cc, std::string) - CONFIG_VALUE_ARRAY_HANDLER(cflags_objc, std::string) - CONFIG_VALUE_ARRAY_HANDLER(cflags_objcc, std::string) - CONFIG_VALUE_ARRAY_HANDLER(rustflags, std::string) - CONFIG_VALUE_ARRAY_HANDLER(defines, std::string) - CONFIG_VALUE_ARRAY_HANDLER(include_dirs, SourceDir) - CONFIG_VALUE_ARRAY_HANDLER(inputs, SourceFile) - CONFIG_VALUE_ARRAY_HANDLER(ldflags, std::string) - CONFIG_VALUE_ARRAY_HANDLER(swiftflags, std::string) + CONFIG_VALUE_ARRAY_HANDLER(arflags, std::string, + kRecursiveWriterKeepDuplicates) + CONFIG_VALUE_ARRAY_HANDLER(asmflags, std::string, + kRecursiveWriterKeepDuplicates) + CONFIG_VALUE_ARRAY_HANDLER(cflags, std::string, + kRecursiveWriterKeepDuplicates) + CONFIG_VALUE_ARRAY_HANDLER(cflags_c, std::string, + kRecursiveWriterKeepDuplicates) + CONFIG_VALUE_ARRAY_HANDLER(cflags_cc, std::string, + kRecursiveWriterKeepDuplicates) + CONFIG_VALUE_ARRAY_HANDLER(cflags_objc, std::string, + kRecursiveWriterKeepDuplicates) + CONFIG_VALUE_ARRAY_HANDLER(cflags_objcc, std::string, + kRecursiveWriterKeepDuplicates) + CONFIG_VALUE_ARRAY_HANDLER(rustflags, std::string, + kRecursiveWriterKeepDuplicates) + CONFIG_VALUE_ARRAY_HANDLER(defines, std::string, + kRecursiveWriterSkipDuplicates) + CONFIG_VALUE_ARRAY_HANDLER(include_dirs, SourceDir, + kRecursiveWriterSkipDuplicates) + CONFIG_VALUE_ARRAY_HANDLER(inputs, SourceFile, + kRecursiveWriterKeepDuplicates) + CONFIG_VALUE_ARRAY_HANDLER(ldflags, std::string, + kRecursiveWriterKeepDuplicates) + CONFIG_VALUE_ARRAY_HANDLER(swiftflags, std::string, + kRecursiveWriterKeepDuplicates) #undef CONFIG_VALUE_ARRAY_HANDLER // Libs and lib_dirs are handled specially below. @@ -814,8 +827,10 @@ // attribution. // This should match RecursiveTargetConfigToStream in the order it traverses. template <class T> - ValuePtr RenderConfigValues(const std::vector<T>& (ConfigValues::*getter)() + ValuePtr RenderConfigValues(RecursiveWriterConfig writer_config, + const std::vector<T>& (ConfigValues::*getter)() const) { + std::set<T> seen; auto res = std::make_unique<base::ListValue>(); for (ConfigValuesIterator iter(target_); !iter.done(); iter.Next()) { const std::vector<T>& vec = (iter.cur().*getter)(); @@ -844,7 +859,24 @@ } } + // If blame is on, then do not de-dup across configs. + if (blame_) + seen.clear(); + for (const T& val : vec) { + switch (writer_config) { + case kRecursiveWriterKeepDuplicates: + break; + + case kRecursiveWriterSkipDuplicates: { + if (seen.find(val) != seen.end()) + continue; + + seen.insert(val); + break; + } + } + ValuePtr rendered = RenderValue(val); std::string str; // Indent string values in blame mode
diff --git a/src/gn/ninja_binary_target_writer.cc b/src/gn/ninja_binary_target_writer.cc index e4b0652..0b7e4ea 100644 --- a/src/gn/ninja_binary_target_writer.cc +++ b/src/gn/ninja_binary_target_writer.cc
@@ -300,8 +300,9 @@ const SourceFile* optional_def_file) { if (tool->AsC()) { // First the ldflags from the target and its config. - RecursiveTargetConfigStringsToStream(target_, &ConfigValues::ldflags, - GetFlagOptions(), out); + RecursiveTargetConfigStringsToStream(kRecursiveWriterKeepDuplicates, + target_, &ConfigValues::ldflags, + GetFlagOptions(), out); } // Followed by library search paths that have been recursively pushed
diff --git a/src/gn/ninja_c_binary_target_writer.cc b/src/gn/ninja_c_binary_target_writer.cc index b52475f..c1432b2 100644 --- a/src/gn/ninja_c_binary_target_writer.cc +++ b/src/gn/ninja_c_binary_target_writer.cc
@@ -228,7 +228,8 @@ // Defines. if (subst.used.count(&CSubstitutionDefines)) { out_ << CSubstitutionDefines.ninja_name << " ="; - RecursiveTargetConfigToStream<std::string>(target_, &ConfigValues::defines, + RecursiveTargetConfigToStream<std::string>(kRecursiveWriterSkipDuplicates, + target_, &ConfigValues::defines, DefineWriter(), out_); out_ << std::endl; } @@ -242,7 +243,7 @@ path_output_.current_dir(), settings_->build_settings()->root_path_utf8(), ESCAPE_NINJA_COMMAND); RecursiveTargetConfigToStream<SourceDir>( - target_, &ConfigValues::framework_dirs, + kRecursiveWriterSkipDuplicates, target_, &ConfigValues::framework_dirs, FrameworkDirsWriter(framework_dirs_output, tool->framework_dir_switch()), out_); @@ -256,7 +257,7 @@ path_output_.current_dir(), settings_->build_settings()->root_path_utf8(), ESCAPE_NINJA_COMMAND); RecursiveTargetConfigToStream<SourceDir>( - target_, &ConfigValues::include_dirs, + kRecursiveWriterSkipDuplicates, target_, &ConfigValues::include_dirs, IncludeWriter(include_path_output), out_); out_ << std::endl; } @@ -278,7 +279,8 @@ EscapeOptions opts = GetFlagOptions(); if (target_->source_types_used().Get(SourceFile::SOURCE_S) || target_->source_types_used().Get(SourceFile::SOURCE_ASM)) { - WriteOneFlag(target_, &CSubstitutionAsmFlags, false, Tool::kToolNone, + WriteOneFlag(kRecursiveWriterKeepDuplicates, target_, + &CSubstitutionAsmFlags, false, Tool::kToolNone, &ConfigValues::asmflags, opts, path_output_, out_); } if (target_->source_types_used().Get(SourceFile::SOURCE_C) || @@ -286,27 +288,31 @@ target_->source_types_used().Get(SourceFile::SOURCE_M) || target_->source_types_used().Get(SourceFile::SOURCE_MM) || target_->source_types_used().Get(SourceFile::SOURCE_MODULEMAP)) { - WriteOneFlag(target_, &CSubstitutionCFlags, false, Tool::kToolNone, - &ConfigValues::cflags, opts, path_output_, out_); + WriteOneFlag(kRecursiveWriterKeepDuplicates, target_, &CSubstitutionCFlags, + false, Tool::kToolNone, &ConfigValues::cflags, opts, + path_output_, out_); } if (target_->source_types_used().Get(SourceFile::SOURCE_C)) { - WriteOneFlag(target_, &CSubstitutionCFlagsC, has_precompiled_headers, - CTool::kCToolCc, &ConfigValues::cflags_c, opts, path_output_, - out_); + WriteOneFlag(kRecursiveWriterKeepDuplicates, target_, &CSubstitutionCFlagsC, + has_precompiled_headers, CTool::kCToolCc, + &ConfigValues::cflags_c, opts, path_output_, out_); } if (target_->source_types_used().Get(SourceFile::SOURCE_CPP) || target_->source_types_used().Get(SourceFile::SOURCE_MODULEMAP)) { - WriteOneFlag(target_, &CSubstitutionCFlagsCc, has_precompiled_headers, + WriteOneFlag(kRecursiveWriterKeepDuplicates, target_, + &CSubstitutionCFlagsCc, has_precompiled_headers, CTool::kCToolCxx, &ConfigValues::cflags_cc, opts, path_output_, out_); } if (target_->source_types_used().Get(SourceFile::SOURCE_M)) { - WriteOneFlag(target_, &CSubstitutionCFlagsObjC, has_precompiled_headers, + WriteOneFlag(kRecursiveWriterKeepDuplicates, target_, + &CSubstitutionCFlagsObjC, has_precompiled_headers, CTool::kCToolObjC, &ConfigValues::cflags_objc, opts, path_output_, out_); } if (target_->source_types_used().Get(SourceFile::SOURCE_MM)) { - WriteOneFlag(target_, &CSubstitutionCFlagsObjCc, has_precompiled_headers, + WriteOneFlag(kRecursiveWriterKeepDuplicates, target_, + &CSubstitutionCFlagsObjCc, has_precompiled_headers, CTool::kCToolObjCxx, &ConfigValues::cflags_objcc, opts, path_output_, out_); } @@ -345,7 +351,8 @@ out_ << std::endl; } - WriteOneFlag(target_, &CSubstitutionSwiftFlags, false, CTool::kCToolSwift, + WriteOneFlag(kRecursiveWriterKeepDuplicates, target_, + &CSubstitutionSwiftFlags, false, CTool::kCToolSwift, &ConfigValues::swiftflags, opts, path_output_, out_); } @@ -471,16 +478,20 @@ // for .gch targets. EscapeOptions opts = GetFlagOptions(); if (tool_name == CTool::kCToolCc) { - RecursiveTargetConfigStringsToStream(target_, &ConfigValues::cflags_c, opts, + RecursiveTargetConfigStringsToStream(kRecursiveWriterKeepDuplicates, + target_, &ConfigValues::cflags_c, opts, out_); } else if (tool_name == CTool::kCToolCxx) { - RecursiveTargetConfigStringsToStream(target_, &ConfigValues::cflags_cc, + RecursiveTargetConfigStringsToStream(kRecursiveWriterKeepDuplicates, + target_, &ConfigValues::cflags_cc, opts, out_); } else if (tool_name == CTool::kCToolObjC) { - RecursiveTargetConfigStringsToStream(target_, &ConfigValues::cflags_objc, + RecursiveTargetConfigStringsToStream(kRecursiveWriterKeepDuplicates, + target_, &ConfigValues::cflags_objc, opts, out_); } else if (tool_name == CTool::kCToolObjCxx) { - RecursiveTargetConfigStringsToStream(target_, &ConfigValues::cflags_objcc, + RecursiveTargetConfigStringsToStream(kRecursiveWriterKeepDuplicates, + target_, &ConfigValues::cflags_objcc, opts, out_); } @@ -834,7 +845,8 @@ out_ << std::endl; } else if (target_->output_type() == Target::STATIC_LIBRARY) { out_ << " arflags ="; - RecursiveTargetConfigStringsToStream(target_, &ConfigValues::arflags, + RecursiveTargetConfigStringsToStream(kRecursiveWriterKeepDuplicates, + target_, &ConfigValues::arflags, GetFlagOptions(), out_); out_ << std::endl; }
diff --git a/src/gn/ninja_rust_binary_target_writer.cc b/src/gn/ninja_rust_binary_target_writer.cc index 568c2b4..82149bf 100644 --- a/src/gn/ninja_rust_binary_target_writer.cc +++ b/src/gn/ninja_rust_binary_target_writer.cc
@@ -207,10 +207,12 @@ EscapeOptions opts = GetFlagOptions(); WriteCrateVars(target_, tool_, opts, out_); - WriteOneFlag(target_, &kRustSubstitutionRustFlags, false, Tool::kToolNone, + WriteOneFlag(kRecursiveWriterKeepDuplicates, target_, + &kRustSubstitutionRustFlags, false, Tool::kToolNone, &ConfigValues::rustflags, opts, path_output_, out_); - WriteOneFlag(target_, &kRustSubstitutionRustEnv, false, Tool::kToolNone, + WriteOneFlag(kRecursiveWriterKeepDuplicates, target_, + &kRustSubstitutionRustEnv, false, Tool::kToolNone, &ConfigValues::rustenv, opts, path_output_, out_); WriteSharedVars(subst);
diff --git a/src/gn/ninja_target_command_util.cc b/src/gn/ninja_target_command_util.cc index 05f4ccd..b542fb2 100644 --- a/src/gn/ninja_target_command_util.cc +++ b/src/gn/ninja_target_command_util.cc
@@ -41,7 +41,8 @@ return ret; } -void WriteOneFlag(const Target* target, +void WriteOneFlag(RecursiveWriterConfig config, + const Target* target, const Substitution* subst_enum, bool has_precompiled_headers, const char* tool_name, @@ -67,16 +68,16 @@ // Enables precompiled headers and names the .h file. It's a string // rather than a file name (so no need to rebase or use path_output). out << " /Yu" << target->config_values().precompiled_header(); - RecursiveTargetConfigStringsToStream(target, getter, flag_escape_options, - out); + RecursiveTargetConfigStringsToStream(config, target, getter, + flag_escape_options, out); } else if (tool && tool->precompiled_header_type() == CTool::PCH_GCC) { // The targets to build the .gch files should omit the -include flag // below. To accomplish this, each substitution flag is overwritten in // the target rule and these values are repeated. The -include flag is // omitted in place of the required -x <header lang> flag for .gch // targets. - RecursiveTargetConfigStringsToStream(target, getter, flag_escape_options, - out); + RecursiveTargetConfigStringsToStream(config, target, getter, + flag_escape_options, out); // Compute the gch file (it will be language-specific). std::vector<OutputFile> outputs; @@ -90,12 +91,12 @@ out << " -include " << pch_file; } } else { - RecursiveTargetConfigStringsToStream(target, getter, flag_escape_options, - out); + RecursiveTargetConfigStringsToStream(config, target, getter, + flag_escape_options, out); } } else { - RecursiveTargetConfigStringsToStream(target, getter, flag_escape_options, - out); + RecursiveTargetConfigStringsToStream(config, target, getter, + flag_escape_options, out); } if (write_substitution)
diff --git a/src/gn/ninja_target_command_util.h b/src/gn/ninja_target_command_util.h index 00f9a77..b0179a1 100644 --- a/src/gn/ninja_target_command_util.h +++ b/src/gn/ninja_target_command_util.h
@@ -92,7 +92,8 @@ // The tool_type indicates the corresponding tool for flags that are // tool-specific (e.g. "cflags_c"). For non-tool-specific flags (e.g. // "defines") tool_type should be TYPE_NONE. -void WriteOneFlag(const Target* target, +void WriteOneFlag(RecursiveWriterConfig config, + const Target* target, const Substitution* subst_enum, bool has_precompiled_headers, const char* tool_name,
diff --git a/src/gn/visual_studio_writer.cc b/src/gn/visual_studio_writer.cc index f6ea9d2..c47c910 100644 --- a/src/gn/visual_studio_writer.cc +++ b/src/gn/visual_studio_writer.cc
@@ -547,8 +547,8 @@ std::unique_ptr<XmlElementWriter> include_dirs = cl_compile->SubElement("AdditionalIncludeDirectories"); RecursiveTargetConfigToStream<SourceDir>( - target, &ConfigValues::include_dirs, IncludeDirWriter(path_output), - include_dirs->StartContent(false)); + kRecursiveWriterSkipDuplicates, target, &ConfigValues::include_dirs, + IncludeDirWriter(path_output), include_dirs->StartContent(false)); include_dirs->Text(windows_kits_include_dirs_ + "$(VSInstallDir)\\VC\\atlmfc\\include;" + "%(AdditionalIncludeDirectories)"); @@ -583,7 +583,8 @@ std::unique_ptr<XmlElementWriter> preprocessor_definitions = cl_compile->SubElement("PreprocessorDefinitions"); RecursiveTargetConfigToStream<std::string>( - target, &ConfigValues::defines, SemicolonSeparatedWriter(), + kRecursiveWriterSkipDuplicates, target, &ConfigValues::defines, + SemicolonSeparatedWriter(), preprocessor_definitions->StartContent(false)); preprocessor_definitions->Text("%(PreprocessorDefinitions)"); }