Allow replacing hardcoded "ninja.exe" in VS generated projects
By specifying the --ninja-executable flag, we can generate VS projects
that invoke a wrapper around ninja.exe, instead of invoking ninja.exe
directly.
The behavior is unchanged if the --ninja-executable flag is not set.
Also s/master/main in README.md
Change-Id: I3b7a30b355976139723f47da5bf8965645dd40d1
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/11680
Reviewed-by: Scott Graham <scottmg@chromium.org>
diff --git a/README.md b/README.md
index d6c9118..f62e28f 100644
--- a/README.md
+++ b/README.md
@@ -5,10 +5,10 @@
Related resources:
- * Documentation in [docs/](https://gn.googlesource.com/gn/+/master/docs/). In
+ * Documentation in [docs/](https://gn.googlesource.com/gn/+/main/docs/). In
particular [GN Quick Start
- guide](https://gn.googlesource.com/gn/+/master/docs/quick_start.md)
- and the [reference](https://gn.googlesource.com/gn/+/master/docs/reference.md)
+ guide](https://gn.googlesource.com/gn/+/main/docs/quick_start.md)
+ and the [reference](https://gn.googlesource.com/gn/+/main/docs/reference.md)
(the latter is all builtin help converted to a single file).
* An introductory [presentation](https://docs.google.com/presentation/d/15Zwb53JcncHfEwHpnG_PoIbbzQ3GQi_cpujYwbpcbZo/edit?usp=sharing).
* The [mailing list](https://groups.google.com/a/chromium.org/forum/#!forum/gn-dev).
@@ -124,10 +124,10 @@
* [Compiler setup](https://cs.chromium.org/chromium/src/build/config/compiler/BUILD.gn)
and the Fuchsia setup:
- * [.gn](https://fuchsia.googlesource.com/fuchsia/+/refs/heads/master/.gn)
- * [BUILDCONFIG.gn](https://fuchsia.googlesource.com/fuchsia/+/refs/heads/master/build/config/BUILDCONFIG.gn)
- * [Toolchain setup](https://fuchsia.googlesource.com/fuchsia/+/refs/heads/master/build/toolchain/)
- * [Compiler setup](https://fuchsia.googlesource.com/fuchsia/+/refs/heads/master/build/config/BUILD.gn)
+ * [.gn](https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/.gn)
+ * [BUILDCONFIG.gn](https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/build/config/BUILDCONFIG.gn)
+ * [Toolchain setup](https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/build/toolchain/)
+ * [Compiler setup](https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/build/config/BUILD.gn)
## Reporting bugs
@@ -147,7 +147,7 @@
Then, to upload a change for review:
git commit
- git push origin HEAD:refs/for/master
+ git push origin HEAD:refs/for/main
The first time you do this you'll get an error from the server about a missing
change-ID. Follow the directions in the error message to install the change-ID
@@ -156,7 +156,7 @@
When revising a change, use:
git commit --amend
- git push origin HEAD:refs/for/master
+ git push origin HEAD:refs/for/main
which will add the new changes to the existing code review, rather than creating
a new one.
@@ -193,7 +193,7 @@
your own.
GN does not guarantee the backwards-compatibility of new versions and has no
-branches or versioning scheme beyond the sequence of commits to the master git
+branches or versioning scheme beyond the sequence of commits to the main git
branch (which is expected to be stable).
In practice, however, GN is very backwards-compatible. The core functionality
diff --git a/src/gn/command_gen.cc b/src/gn/command_gen.cc
index e5248b9..0f4ed70 100644
--- a/src/gn/command_gen.cc
+++ b/src/gn/command_gen.cc
@@ -229,13 +229,19 @@
if (command_line->HasSwitch(kSwitchIdeValueWinSdk))
win_kit = command_line->GetSwitchValueASCII(kSwitchIdeValueWinSdk);
std::string ninja_extra_args;
- if (command_line->HasSwitch(kSwitchNinjaExtraArgs))
+ if (command_line->HasSwitch(kSwitchNinjaExtraArgs)) {
ninja_extra_args =
command_line->GetSwitchValueASCII(kSwitchNinjaExtraArgs);
+ }
+ std::string ninja_executable;
+ if (command_line->HasSwitch(kSwitchNinjaExecutable)) {
+ ninja_executable =
+ command_line->GetSwitchValueASCII(kSwitchNinjaExecutable);
+ }
bool no_deps = command_line->HasSwitch(kSwitchNoDeps);
bool res = VisualStudioWriter::RunAndWriteFiles(
build_settings, builder, version, sln_name, filters, win_kit,
- ninja_extra_args, no_deps, err);
+ ninja_extra_args, ninja_executable, no_deps, err);
if (res && !quiet) {
OutputString("Generating Visual Studio projects took " +
base::Int64ToString(timer.Elapsed().InMilliseconds()) +
diff --git a/src/gn/visual_studio_writer.cc b/src/gn/visual_studio_writer.cc
index c47c910..e88a469 100644
--- a/src/gn/visual_studio_writer.cc
+++ b/src/gn/visual_studio_writer.cc
@@ -241,6 +241,10 @@
return true;
}
+std::string GetNinjaExecutable(const std::string& ninja_executable) {
+ return ninja_executable.empty() ? "ninja.exe" : ninja_executable;
+}
+
} // namespace
VisualStudioWriter::SolutionEntry::SolutionEntry(const std::string& _name,
@@ -324,6 +328,7 @@
const std::string& filters,
const std::string& win_sdk,
const std::string& ninja_extra_args,
+ const std::string& ninja_executable,
bool no_deps,
Err* err) {
std::vector<const Target*> targets;
@@ -361,7 +366,8 @@
continue;
}
- if (!writer.WriteProjectFiles(target, ninja_extra_args, err))
+ if (!writer.WriteProjectFiles(target, ninja_extra_args, ninja_executable,
+ err))
return false;
}
@@ -384,6 +390,7 @@
bool VisualStudioWriter::WriteProjectFiles(const Target* target,
const std::string& ninja_extra_args,
+ const std::string& ninja_executable,
Err* err) {
std::string project_name = target->label().name();
const char* project_config_platform = config_platform_;
@@ -416,7 +423,8 @@
std::ostream vcxproj_string_out(&vcxproj_storage);
SourceFileCompileTypePairs source_types;
if (!WriteProjectFileContents(vcxproj_string_out, *projects_.back(), target,
- ninja_extra_args, &source_types, err)) {
+ ninja_extra_args, ninja_executable,
+ &source_types, err)) {
projects_.pop_back();
return false;
}
@@ -440,6 +448,7 @@
const SolutionProject& solution_project,
const Target* target,
const std::string& ninja_extra_args,
+ const std::string& ninja_executable,
SourceFileCompileTypePairs* source_types,
Err* err) {
PathOutput path_output(
@@ -526,6 +535,7 @@
project.SubElement("PropertyGroup", XmlAttributes("Label", "UserMacros"));
std::string ninja_target = GetNinjaTarget(target);
+ std::string ninja_exe = GetNinjaExecutable(ninja_executable);
{
std::unique_ptr<XmlElementWriter> properties =
@@ -622,9 +632,9 @@
compile_type = "CustomBuild";
std::unique_ptr<XmlElementWriter> build = group->SubElement(
compile_type, "Include", SourceFileWriter(path_output, file));
- build->SubElement("Command")->Text("call ninja.exe -C $(OutDir) " +
- ninja_extra_args + " " +
- tool_outputs[0].value());
+ build->SubElement("Command")->Text("call " + ninja_exe +
+ " -C $(OutDir) " + ninja_extra_args +
+ " " + tool_outputs[0].value());
build->SubElement("Outputs")->Text("$(OutDir)" +
tool_outputs[0].value());
} else {
@@ -650,7 +660,7 @@
project.SubElement("Target", XmlAttributes("Name", "Build"));
build->SubElement(
"Exec",
- XmlAttributes("Command", "call ninja.exe -C $(OutDir) " +
+ XmlAttributes("Command", "call " + ninja_exe + " -C $(OutDir) " +
ninja_extra_args + " " + ninja_target));
}
@@ -660,7 +670,8 @@
clean->SubElement(
"Exec",
XmlAttributes("Command",
- "call ninja.exe -C $(OutDir) -tclean " + ninja_target));
+ "call " + ninja_exe + " -C $(OutDir) -tclean " +
+ ninja_target));
}
return true;
diff --git a/src/gn/visual_studio_writer.h b/src/gn/visual_studio_writer.h
index e4957a1..8d1bc8e 100644
--- a/src/gn/visual_studio_writer.h
+++ b/src/gn/visual_studio_writer.h
@@ -47,6 +47,7 @@
const std::string& filters,
const std::string& win_sdk,
const std::string& ninja_extra_args,
+ const std::string& ninja_executable,
bool no_deps,
Err* err);
@@ -55,6 +56,7 @@
FRIEND_TEST_ALL_PREFIXES(VisualStudioWriterTest,
ResolveSolutionFolders_AbsPath);
FRIEND_TEST_ALL_PREFIXES(VisualStudioWriterTest, NoDotSlash);
+ FRIEND_TEST_ALL_PREFIXES(VisualStudioWriterTest, NinjaExecutable);
// Solution project or folder.
struct SolutionEntry {
@@ -109,11 +111,13 @@
bool WriteProjectFiles(const Target* target,
const std::string& ninja_extra_args,
+ const std::string& ninja_executable,
Err* err);
bool WriteProjectFileContents(std::ostream& out,
const SolutionProject& solution_project,
const Target* target,
const std::string& ninja_extra_args,
+ const std::string& ninja_executable,
SourceFileCompileTypePairs* source_types,
Err* err);
void WriteFiltersFileContents(std::ostream& out,
diff --git a/src/gn/visual_studio_writer_unittest.cc b/src/gn/visual_studio_writer_unittest.cc
index 5e89fe1..01271a3 100644
--- a/src/gn/visual_studio_writer_unittest.cc
+++ b/src/gn/visual_studio_writer_unittest.cc
@@ -193,8 +193,54 @@
std::stringstream file_contents;
writer.WriteProjectFileContents(file_contents, *writer.projects_.back(),
- &target, "", &source_types, &err);
+ &target, "", "", &source_types, &err);
// Should find args of a ninja clean command, with no ./ before the file name.
ASSERT_NE(file_contents.str().find("-tclean baz"), std::string::npos);
}
+
+TEST_F(VisualStudioWriterTest, NinjaExecutable) {
+ VisualStudioWriter writer(setup_.build_settings(), "Win32",
+ VisualStudioWriter::Version::Vs2015,
+ "10.0.17134.0");
+
+ std::string path = MakeTestPath("blah.vcxproj");
+ writer.projects_.push_back(
+ std::make_unique<VisualStudioWriter::SolutionProject>(
+ "base", path, MakeGuid(path, "project"), MakeTestPath("/foo"),
+ "Win32"));
+
+ std::unique_ptr<Tool> tool = Tool::CreateTool(CTool::kCToolAlink);
+ tool->set_outputs(SubstitutionList::MakeForTest(
+ "{{root_out_dir}}/{{target_output_name}}{{output_extension}}", ""));
+
+ Toolchain toolchain(setup_.settings(), Label(SourceDir("//tc/"), "tc"));
+ toolchain.SetTool(std::move(tool));
+
+ Target target(setup_.settings(), Label(SourceDir("//baz/"), "baz"));
+ target.set_output_type(Target::STATIC_LIBRARY);
+ target.SetToolchain(&toolchain);
+
+ Err err;
+ ASSERT_TRUE(target.OnResolved(&err));
+
+ VisualStudioWriter::SourceFileCompileTypePairs source_types;
+
+ std::stringstream file_contents_without_flag;
+ writer.WriteProjectFileContents(file_contents_without_flag,
+ *writer.projects_.back(), &target, "", "",
+ &source_types, &err);
+
+ // Should default to ninja.exe if ninja_executable flag is not set.
+ ASSERT_NE(file_contents_without_flag.str().find("call ninja.exe"),
+ std::string::npos);
+
+ std::stringstream file_contents_with_flag;
+ writer.WriteProjectFileContents(file_contents_with_flag,
+ *writer.projects_.back(), &target, "",
+ "ninja_wrapper.exe", &source_types, &err);
+
+ // Should use ninja_wrapper.exe because ninja_executable flag is set.
+ ASSERT_NE(file_contents_with_flag.str().find("call ninja_wrapper.exe"),
+ std::string::npos);
+}