Browse Source

configure_file: canonicalize input and output path in dependencies

Represent the input file path internally in canonical form.  Otherwise
multiple `configure_file` calls that share the same input file but specify
it relative to different directories (e.g. via `../`) result in multiple
copies of the dependency on the rule to re-run CMake.  This causes the
Ninja generator to emit duplicate phony build statements for these
dependencies, which generates an error with `-w dupbuild=err`, which
will be default in Ninja 1.9.

Also canonicalize the output path for consistency.

Add a test case.

Fixes: #18584
Frank Benkstein 7 years ago
parent
commit
6199637e95

+ 4 - 10
Source/cmConfigureFileCommand.cxx

@@ -20,11 +20,8 @@ bool cmConfigureFileCommand::InitialPass(std::vector<std::string> const& args,
   }
 
   std::string const& inFile = args[0];
-  if (!cmSystemTools::FileIsFullPath(inFile)) {
-    this->InputFile = this->Makefile->GetCurrentSourceDirectory();
-    this->InputFile += "/";
-  }
-  this->InputFile += inFile;
+  this->InputFile = cmSystemTools::CollapseFullPath(
+    inFile, this->Makefile->GetCurrentSourceDirectory());
 
   // If the input location is a directory, error out.
   if (cmSystemTools::FileIsDirectory(this->InputFile)) {
@@ -39,11 +36,8 @@ bool cmConfigureFileCommand::InitialPass(std::vector<std::string> const& args,
   }
 
   std::string const& outFile = args[1];
-  if (!cmSystemTools::FileIsFullPath(outFile)) {
-    this->OutputFile = this->Makefile->GetCurrentBinaryDirectory();
-    this->OutputFile += "/";
-  }
-  this->OutputFile += outFile;
+  this->OutputFile = cmSystemTools::CollapseFullPath(
+    outFile, this->Makefile->GetCurrentBinaryDirectory());
 
   // If the output location is already a directory put the file in it.
   if (cmSystemTools::FileIsDirectory(this->OutputFile)) {

+ 5 - 0
Tests/RunCMake/Ninja/PreventConfigureFileDupBuildRule.cmake

@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 3.12)
+project(Test LANGUAGES C)
+
+configure_file(PreventConfigureFileDupBuildRule.cmake PreventTargetAliasesDupBuildRule.cmake @ONLY)
+add_subdirectory(SubDirConfigureFileDup)

+ 7 - 0
Tests/RunCMake/Ninja/RunCMakeTest.cmake

@@ -286,3 +286,10 @@ function (run_PreventTargetAliasesDupBuildRule)
   run_ninja("${RunCMake_TEST_BINARY_DIR}" -w dupbuild=err)
 endfunction ()
 run_PreventTargetAliasesDupBuildRule()
+
+function (run_PreventConfigureFileDupBuildRule)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/PreventConfigureFileDupBuildRule-build)
+  run_cmake(PreventConfigureFileDupBuildRule)
+  run_ninja("${RunCMake_TEST_BINARY_DIR}" -w dupbuild=err)
+endfunction()
+run_PreventConfigureFileDupBuildRule()

+ 1 - 0
Tests/RunCMake/Ninja/SubDirConfigureFileDup/CMakeLists.txt

@@ -0,0 +1 @@
+configure_file(../PreventConfigureFileDupBuildRule.cmake PreventTargetAliasesDupBuildRule.cmake @ONLY)

+ 1 - 1
Tests/RunCMake/configure_file/DirInput-stderr.txt

@@ -1,7 +1,7 @@
 CMake Error at DirInput.cmake:[0-9]+ \(configure_file\):
   configure_file input location
 
-    .*/Tests/RunCMake/configure_file/.
+    .*/Tests/RunCMake/configure_file
 
   is a directory but a file was expected.
 Call Stack \(most recent call first\):