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