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)");
}