Ninja: Fix depfile binding with spaces in path

In build statements we use a single `DEP_FILE = ...` binding that is
shared between `depfile = $DEP_FILE` and `command = ... $DEP_FILE ...`
bindings in the corresponding rule.  In cases that the command's shell
argument needs quoting, add a separate `depfile = ...` binding to the
build statement to express the depfile path without quoting.  Otherwise
`ninja` tries to open a file path that contains literal quotes.

Fixes: #26287
This commit is contained in:
Brad King
2024-09-12 10:54:56 -04:00
parent ad66be9943
commit b11323f1e4
8 changed files with 78 additions and 8 deletions

View File

@@ -2495,16 +2495,22 @@ void cmNinjaTargetGenerator::MacOSXContentGeneratorType::operator()(
this->Generator->Configs[config].ExtraFiles.push_back(std::move(output));
}
void cmNinjaTargetGenerator::AddDepfileBinding(
cmNinjaVars& vars, std::string const& depfile) const
void cmNinjaTargetGenerator::AddDepfileBinding(cmNinjaVars& vars,
std::string depfile) const
{
vars["DEP_FILE"] = this->GetLocalGenerator()->ConvertToOutputFormat(
depfile, cmOutputConverter::SHELL);
std::string depfileForShell =
this->GetLocalGenerator()->ConvertToOutputFormat(depfile,
cmOutputConverter::SHELL);
if (depfile != depfileForShell) {
vars["depfile"] = std::move(depfile);
}
vars["DEP_FILE"] = std::move(depfileForShell);
}
void cmNinjaTargetGenerator::RemoveDepfileBinding(cmNinjaVars& vars) const
{
vars.erase("DEP_FILE");
vars.erase("depfile");
}
void cmNinjaTargetGenerator::addPoolNinjaVariable(

View File

@@ -42,7 +42,7 @@ public:
std::string GetTargetName() const;
void AddDepfileBinding(cmNinjaVars& vars, std::string const& depfile) const;
void AddDepfileBinding(cmNinjaVars& vars, std::string depfile) const;
void RemoveDepfileBinding(cmNinjaVars& vars) const;
protected:

View File

@@ -3,13 +3,29 @@ enable_language(C)
add_executable(main CompileDepends.c)
target_include_directories(main PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
set(CODE_WITH_SPACE [[
add_executable(main2 ../CompileDepends.c)
target_include_directories(main2 PRIVATE ${CMAKE_BINARY_DIR})
]])
if(MAKE_SUPPORTS_SPACES)
add_subdirectory("With Space")
set(check_pairs_with_space "
\"$<TARGET_FILE:main2>|${CMAKE_CURRENT_BINARY_DIR}/CompileDepends.h\"
")
set(check_exes_with_space "
\"$<TARGET_FILE:main2>\"
")
endif()
file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/check-$<LOWER_CASE:$<CONFIG>>.cmake CONTENT "
cmake_minimum_required(VERSION ${CMAKE_VERSION})
set(check_pairs
\"$<TARGET_FILE:main>|${CMAKE_CURRENT_BINARY_DIR}/CompileDepends.h\"
${check_pairs_with_space}
)
set(check_exes
\"$<TARGET_FILE:main>\"
${check_exes_with_space}
)
if (RunCMake_GENERATOR MATCHES \"Make\" AND check_step EQUAL 2)
@@ -17,6 +33,7 @@ if (RunCMake_GENERATOR MATCHES \"Make\" AND check_step EQUAL 2)
if (NOT CMAKE_DEPEND_INFO_FILES)
set(RunCMake_TEST_FAILED \"Variable CMAKE_DEPEND_INFO_FILES not found.\")
else()
list(FILTER CMAKE_DEPEND_INFO_FILES EXCLUDE REGEX main2)
foreach(DEPEND_INFO_FILE IN LISTS CMAKE_DEPEND_INFO_FILES)
include(\"${CMAKE_CURRENT_BINARY_DIR}/\${DEPEND_INFO_FILE}\")
if (NOT CMAKE_DEPENDS_DEPENDENCY_FILES)

View File

@@ -1,3 +1,4 @@
cmake_policy(SET CMP0116 NEW)
enable_language(C)
add_custom_command(OUTPUT main.c
@@ -10,14 +11,38 @@ add_custom_target(mainc ALL DEPENDS main.c)
add_executable(main ${CMAKE_CURRENT_BINARY_DIR}/main.c)
set(CODE_WITH_SPACE [[
add_custom_command(OUTPUT main2.c
DEPFILE main2.c.d
COMMAND "${CMAKE_COMMAND}" -DINFILE=../main.c.in -DOUTFILE=main2.c -DDEPFILE=main2.c.d
-P "${CMAKE_SOURCE_DIR}/GenerateDepFile.cmake"
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
add_custom_target(main2c ALL DEPENDS main2.c)
add_executable(main2 ${CMAKE_CURRENT_BINARY_DIR}/main2.c)
]])
if(MAKE_SUPPORTS_SPACES)
add_subdirectory("With Space")
set(check_pairs_with_space "
\"$<TARGET_FILE:main2>|${CMAKE_CURRENT_BINARY_DIR}/main.c.in\"
\"$<TARGET_FILE:main2>|${CMAKE_CURRENT_BINARY_DIR}/With Space/main2.c\"
")
set(check_exes_with_space "
\"$<TARGET_FILE:main2>\"
")
endif()
file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/check-$<LOWER_CASE:$<CONFIG>>.cmake CONTENT "
cmake_minimum_required(VERSION 3.19)
set(check_pairs
\"$<TARGET_FILE:main>|${CMAKE_CURRENT_BINARY_DIR}/main.c.in\"
\"$<TARGET_FILE:main>|${CMAKE_CURRENT_BINARY_DIR}/main.c\"
${check_pairs_with_space}
)
set(check_exes
\"$<TARGET_FILE:main>\"
${check_exes_with_space}
)
if (RunCMake_GENERATOR MATCHES \"Make\" AND check_step EQUAL 2)
@@ -25,6 +50,7 @@ if (RunCMake_GENERATOR MATCHES \"Make\" AND check_step EQUAL 2)
if (NOT CMAKE_DEPEND_INFO_FILES)
set(RunCMake_TEST_FAILED \"Variable CMAKE_DEPEND_INFO_FILES not found.\")
else()
list(FILTER CMAKE_DEPEND_INFO_FILES EXCLUDE REGEX main2)
foreach(DEPEND_INFO_FILE IN LISTS CMAKE_DEPEND_INFO_FILES)
include(\"${CMAKE_CURRENT_BINARY_DIR}/\${DEPEND_INFO_FILE}\")
if (NOT CMAKE_DEPENDS_DEPENDENCY_FILES)

View File

@@ -11,10 +11,28 @@ add_executable(LinkDependsExe LinkDependsExe.c)
target_link_directories(LinkDependsExe PRIVATE "${EXTERNAL_DIR}")
target_link_libraries(LinkDependsExe PRIVATE External)
set(CODE_WITH_SPACE [[
add_library(LinkDependsLib2 SHARED ../LinkDependsLib.c)
target_link_directories(LinkDependsLib2 PRIVATE "${EXTERNAL_DIR}")
target_link_libraries(LinkDependsLib2 PRIVATE External)
add_executable(LinkDependsExe2 ../LinkDependsExe.c)
target_link_directories(LinkDependsExe2 PRIVATE "${EXTERNAL_DIR}")
target_link_libraries(LinkDependsExe2 PRIVATE External)
]])
if(MAKE_SUPPORTS_SPACES)
add_subdirectory("With Space")
set(check_pairs_with_space "
\"$<TARGET_FILE:LinkDependsLib2>|${EXTERNAL_LIBRARY}\"
\"$<TARGET_FILE:LinkDependsExe2>|${EXTERNAL_LIBRARY}\"
")
endif()
file(GENERATE OUTPUT "${CMAKE_BINARY_DIR}/check-$<LOWER_CASE:$<CONFIG>>.cmake"
CONTENT "
set(check_pairs
\"$<TARGET_FILE:LinkDependsLib>|${EXTERNAL_LIBRARY}\"
\"$<TARGET_FILE:LinkDependsExe>|${EXTERNAL_LIBRARY}\"
${check_pairs_with_space}
)
")

View File

@@ -33,6 +33,7 @@ function(run_BuildDepends CASE)
if(NOT RunCMake_GENERATOR_IS_MULTI_CONFIG)
set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Debug)
endif()
list(APPEND RunCMake_TEST_OPTIONS ${ARGN})
file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
include(${RunCMake_SOURCE_DIR}/${CASE}.step1.cmake OPTIONAL)
@@ -173,8 +174,8 @@ if ((RunCMake_GENERATOR STREQUAL "Unix Makefiles"
AND CMAKE_C_COMPILER_ID STREQUAL "MSVC")
OR RunCMake_GENERATOR MATCHES "Ninja"
)
run_BuildDepends(CompileDepends)
run_BuildDepends(CustomCommandDepends)
run_BuildDepends(CompileDepends -DMAKE_SUPPORTS_SPACES=${MAKE_SUPPORTS_SPACES})
run_BuildDepends(CustomCommandDepends -DMAKE_SUPPORTS_SPACES=${MAKE_SUPPORTS_SPACES})
endif()
if (RunCMake_GENERATOR MATCHES "Makefiles")
@@ -210,6 +211,6 @@ if (RunCMake_GENERATOR MATCHES "Make|Ninja")
AND CMAKE_C_LINK_DEPENDS_USE_LINKER)
run_BuildDepends(LinkDependsExternalLibrary)
unset(run_BuildDepends_skip_step_2)
run_BuildDepends(LinkDepends)
run_BuildDepends(LinkDepends -DMAKE_SUPPORTS_SPACES=${MAKE_SUPPORTS_SPACES})
endif()
endif()

View File

@@ -0,0 +1 @@
cmake_language(EVAL CODE "${CODE_WITH_SPACE}")

View File

@@ -340,6 +340,7 @@ if(CMAKE_Fortran_COMPILER)
endif()
add_RunCMake_test(BuildDepends
-DMAKE_SUPPORTS_SPACES=${MAKE_SUPPORTS_SPACES}
-DMSVC_VERSION=${MSVC_VERSION}
-DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID}
-DCMAKE_C_LINK_DEPENDS_USE_COMPILER=${CMAKE_C_LINK_DEPENDS_USE_COMPILER}