From 7083b1949801dcab8b76cd3978261aca7be30c0e Mon Sep 17 00:00:00 2001 From: Robert Maynard Date: Thu, 17 Feb 2022 08:46:09 -0500 Subject: cmake: When given multiple source paths use last instead of first When given two source paths via `-S` or just directory paths prefer the last one. When the paths are mixed always prefer the last `-S` entry. Fixes: #23238 --- Source/cmake.cxx | 41 +++++++++++++++++++--- Source/cmake.h | 23 ++++++++++++ Tests/RunCMake/CommandLine/RunCMakeTest.cmake | 12 +++++++ Tests/RunCMake/CommandLine/S-S-Sdiffers-stderr.txt | 9 +++++ .../RunCMake/CommandLine/S-S-Simplicit-stderr.txt | 9 +++++ Tests/RunCMake/CommandLine/S-S-differs-stderr.txt | 4 +++ .../CommandLine/S-implicit-differs-stderr.txt | 4 +++ .../CommandLine/S-implicit-differs2-stderr.txt | 4 +++ .../CommandLine/S-implicit-differs3-stderr.txt | 4 +++ 9 files changed, 105 insertions(+), 5 deletions(-) create mode 100644 Tests/RunCMake/CommandLine/S-S-Sdiffers-stderr.txt create mode 100644 Tests/RunCMake/CommandLine/S-S-Simplicit-stderr.txt create mode 100644 Tests/RunCMake/CommandLine/S-S-differs-stderr.txt create mode 100644 Tests/RunCMake/CommandLine/S-implicit-differs-stderr.txt create mode 100644 Tests/RunCMake/CommandLine/S-implicit-differs2-stderr.txt create mode 100644 Tests/RunCMake/CommandLine/S-implicit-differs3-stderr.txt diff --git a/Source/cmake.cxx b/Source/cmake.cxx index d80c4bc..fe4d252 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -818,7 +818,8 @@ void cmake::SetArgs(const std::vector& args) } std::string path = cmSystemTools::CollapseFullPath(value); cmSystemTools::ConvertToUnixSlashes(path); - state->SetHomeDirectory(path); + + state->SetHomeDirectoryViaCommandLine(path, HomeDirArgStyle::Dash_S); return true; }; @@ -1486,6 +1487,7 @@ bool cmake::SetDirectoriesFromFile(const std::string& arg) // CMakeLists.txt file. std::string listPath; std::string cachePath; + bool is_source_dir = false; bool is_empty_directory = false; if (cmSystemTools::FileIsDirectory(arg)) { std::string path = cmSystemTools::CollapseFullPath(arg); @@ -1501,6 +1503,7 @@ bool cmake::SetDirectoriesFromFile(const std::string& arg) if (cmSystemTools::FileExists(listFile)) { listPath = path; is_empty_directory = false; + is_source_dir = true; } } else if (cmSystemTools::FileExists(arg)) { std::string fullPath = cmSystemTools::CollapseFullPath(arg); @@ -1545,19 +1548,23 @@ bool cmake::SetDirectoriesFromFile(const std::string& arg) const bool passed_same_path = (listPath == this->GetHomeDirectory()) || (listPath == this->GetHomeOutputDirectory()); bool used_provided_path = - (passed_same_path || no_source_tree || no_build_tree); + (passed_same_path || is_source_dir || no_build_tree); // If there is a CMakeLists.txt file, use it as the source tree. if (!listPath.empty()) { // When invoked with a path that points to an existing CMakeCache // This function is called multiple times with the same path - if (no_source_tree && no_build_tree) { + if (is_source_dir) { + this->SetHomeDirectoryViaCommandLine(listPath, HomeDirArgStyle::Plain); + if (!no_build_tree) { + std::string cwd = cmSystemTools::GetCurrentWorkingDirectory(); + this->SetHomeOutputDirectory(cwd); + } + } else if (no_source_tree && no_build_tree) { this->SetHomeDirectory(listPath); std::string cwd = cmSystemTools::GetCurrentWorkingDirectory(); this->SetHomeOutputDirectory(cwd); - } else if (no_source_tree) { - this->SetHomeDirectory(listPath); } else if (no_build_tree) { this->SetHomeOutputDirectory(listPath); } @@ -1773,6 +1780,30 @@ void cmake::PrintPresetList(const cmCMakePresetsGraph& graph) const } #endif +void cmake::SetHomeDirectoryViaCommandLine(std::string const& path, + HomeDirArgStyle argStyle) +{ + bool fromDashS = argStyle == HomeDirArgStyle::Dash_S; + static bool homeDirectorySetExplicitly = false; + if (path.empty()) { + return; + } + + auto prev_path = this->GetHomeDirectory(); + if (prev_path != path && !prev_path.empty()) { + const bool ignore_prev_path = + (fromDashS || (!fromDashS && !homeDirectorySetExplicitly)); + const std::string& ignored_path = (ignore_prev_path) ? prev_path : path; + this->IssueMessage(MessageType::WARNING, + cmStrCat("Ignoring extra path from command line:\n \"", + ignored_path, "\"")); + } + if (fromDashS || !homeDirectorySetExplicitly) { + this->SetHomeDirectory(path); + } + homeDirectorySetExplicitly = fromDashS; +} + void cmake::SetHomeDirectory(const std::string& dir) { this->State->SetSourceDirectory(dir); diff --git a/Source/cmake.h b/Source/cmake.h index 97444b8..9c795c5 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -183,6 +183,29 @@ public: #endif std::string ReportCapabilities() const; + enum class HomeDirArgStyle + { + Plain, + Dash_S, + }; + + /** + * Set the home directory from `-S` or from a known location + * that contains a CMakeLists.txt. Will generate warnings + * when overriding an existing source directory. + * + * | args | src dir| warning | + * | ----------------- | ------ | -------------- | + * | `dirA dirA` | dirA | N/A | + * | `-S dirA -S dirA` | dirA | N/A | + * | `-S dirA -S dirB` | dirB | Ignoring dirA | + * | `-S dirA dirB` | dirA | Ignoring dirB | + * | `dirA -S dirB` | dirB | Ignoring dirA | + * | `dirA dirB` | dirB | Ignoring dirA | + */ + void SetHomeDirectoryViaCommandLine(std::string const& path, + HomeDirArgStyle argStyle); + //@{ /** * Set/Get the home directory (or output directory) in the project. The diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake index 5944d2d..17adefd 100644 --- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake +++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake @@ -168,6 +168,18 @@ endif() run_cmake_with_raw_args(S-B-non-path "-S \"${source_dir}\" -B \"${binary_dir}\" \"\"") run_cmake_with_raw_args(S-B-non-path2 "-S \"${source_dir}\" \"\" -B \"${binary_dir}\"") + file(REMOVE_RECURSE "${binary_dir}/other_dir") + file(MAKE_DIRECTORY "${binary_dir}/other_dir") + file(WRITE "${binary_dir}/other_dir/CMakeLists.txt" [=[ ]=]) + run_cmake_with_options(S-S-same -S ${source_dir} -S ${source_dir} -B ${binary_dir}) + run_cmake_with_options(S-S-differs -S ${binary_dir}/other_dir -S ${source_dir} -B ${binary_dir}) + run_cmake_with_options(S-implicit-same -S ${source_dir} ${source_dir} -B ${binary_dir}) + run_cmake_with_options(S-implicit-differs -S ${source_dir} ${binary_dir}/other_dir -B ${binary_dir}) + run_cmake_with_options(S-implicit-differs2 ${binary_dir}/other_dir -S ${source_dir} -B ${binary_dir}) + run_cmake_with_options(S-implicit-differs3 ${binary_dir}/other_dir ${source_dir} -B ${binary_dir}) + run_cmake_with_options(S-S-Sdiffers -S ${binary_dir}/other_dir1 -S ${binary_dir}/other_dir2 -S ${source_dir} -B ${binary_dir}) + run_cmake_with_options(S-S-Simplicit ${binary_dir}/other_dir1 ${binary_dir}/other_dir2 ${source_dir} -B ${binary_dir}) + # make sure that -B can explicitly construct build directories file(REMOVE_RECURSE "${binary_dir}") run_cmake_with_options(B-arg -B ${binary_dir} ${source_dir}) diff --git a/Tests/RunCMake/CommandLine/S-S-Sdiffers-stderr.txt b/Tests/RunCMake/CommandLine/S-S-Sdiffers-stderr.txt new file mode 100644 index 0000000..43869db --- /dev/null +++ b/Tests/RunCMake/CommandLine/S-S-Sdiffers-stderr.txt @@ -0,0 +1,9 @@ +^CMake Warning: + Ignoring extra path from command line: + + .*other_dir1" +.* +CMake Warning: + Ignoring extra path from command line: + + .*other_dir2"$ diff --git a/Tests/RunCMake/CommandLine/S-S-Simplicit-stderr.txt b/Tests/RunCMake/CommandLine/S-S-Simplicit-stderr.txt new file mode 100644 index 0000000..43869db --- /dev/null +++ b/Tests/RunCMake/CommandLine/S-S-Simplicit-stderr.txt @@ -0,0 +1,9 @@ +^CMake Warning: + Ignoring extra path from command line: + + .*other_dir1" +.* +CMake Warning: + Ignoring extra path from command line: + + .*other_dir2"$ diff --git a/Tests/RunCMake/CommandLine/S-S-differs-stderr.txt b/Tests/RunCMake/CommandLine/S-S-differs-stderr.txt new file mode 100644 index 0000000..5714130 --- /dev/null +++ b/Tests/RunCMake/CommandLine/S-S-differs-stderr.txt @@ -0,0 +1,4 @@ +^CMake Warning: + Ignoring extra path from command line: + + .*ExplicitDirs-build/other_dir.* diff --git a/Tests/RunCMake/CommandLine/S-implicit-differs-stderr.txt b/Tests/RunCMake/CommandLine/S-implicit-differs-stderr.txt new file mode 100644 index 0000000..18f0d16 --- /dev/null +++ b/Tests/RunCMake/CommandLine/S-implicit-differs-stderr.txt @@ -0,0 +1,4 @@ +^CMake Warning: + Ignoring extra path from command line: + + .*other_dir"$ diff --git a/Tests/RunCMake/CommandLine/S-implicit-differs2-stderr.txt b/Tests/RunCMake/CommandLine/S-implicit-differs2-stderr.txt new file mode 100644 index 0000000..5714130 --- /dev/null +++ b/Tests/RunCMake/CommandLine/S-implicit-differs2-stderr.txt @@ -0,0 +1,4 @@ +^CMake Warning: + Ignoring extra path from command line: + + .*ExplicitDirs-build/other_dir.* diff --git a/Tests/RunCMake/CommandLine/S-implicit-differs3-stderr.txt b/Tests/RunCMake/CommandLine/S-implicit-differs3-stderr.txt new file mode 100644 index 0000000..5714130 --- /dev/null +++ b/Tests/RunCMake/CommandLine/S-implicit-differs3-stderr.txt @@ -0,0 +1,4 @@ +^CMake Warning: + Ignoring extra path from command line: + + .*ExplicitDirs-build/other_dir.* -- cgit v0.12