有几个问题可能会导致这种情况。它主要与Windows相关。这更多是在 cmake 方面,但它解决了在 Windows 中使用 CMake 时可能遇到的一些特定于 Windows 的问题。这在我脑海中很新鲜,并且突然出现,所以我将把它放在这里。开始了。
1.如果路径中有空格,CMake将分隔一个变量以列出。
如果您从 CMake 中调用另一个 CMake 实例,发送程序文件路径将对这些字符串进行切片,并将您的变量分成 3 项列表。空格将被分号分隔符替换。
set(CMAKE_EXE C:\Program Files (x86)\CMake\bin\cmake.exe)
"C:\Program;Files;(x86)\CMake\bin\cmake.exe <- CMAKE_EXE is now a 3 item list separated by ; "
list(LENGTH ${CMAKE_EXE} count)
message("CMAKE_EXE has ${count} items") "-> displays 3"
在 Windows 上,所有路径变量都应该用引号括起来,以推断它们是 1 个单字符串变量。不仅适用于 cmake,还适用于批处理脚本、基本命令行等。
set(CMAKE_EXE "C:/Program Files (x86)/CMake/bin/cmake.exe")
现在,每当您引用 CMAKE_EXE 时,您都需要始终将其括在引号中,因为否则 cmake 会再次将其分解为列表。
execute_command(COMMAND cmd /c ${CMAKE_EXE} -P myScript.cmake) <-- BAD
execute_command(COMMAND cmd /c "${CMAKE_EXE}" -P myScript.cmake) <- GOOD
只要养成总是在你引用的路径周围加上引号的习惯。
2.远离Windows反斜杠!
默认情况下,Windows 使用反斜杠作为路径分隔符,这是大多数编码语言(包括 CMake)中的转义序列。只需发送窗口/正斜杠即可。这消除了您在字符串文字中加倍转义字符以匹配路径时遇到的任何麻烦。\
请记住,Windows 总是会尝试为您提供 \ 格式的路径。Windows 喜欢在某些地方使用反斜杠,例如环境路径和设置文件,而 cmake 喜欢正斜杠。您有时需要在不同格式之间进行转换。使用类似这样的东西将路径转换为更加跨平台兼容。您可以在现有变量上替换“就地”。
"CMAKE_EXE = C:\Program Files (x86)\CMake\bin\cmake.exe <- value before"
string(REPLACE "\\" "/" CMAKE_EXE "${CMAKE_EXE}") "<- notice the quotes again"
"CMAKE_EXE = C:/Program Files (x86)/CMake/bin/cmake.exe <- value after"
看看这些设计用于进行路径转换的 CMake 函数。
https://cmake.org/cmake/help/latest/command/file.html#to-native-path
3. 有时,Windows 将不带引号的路径解释为 8.3SFN (8DOT3) 格式
8.3 文件名
在 MSDOS 和 Windows 95 时代,我们处理的是 FAT 文件系统和 8.3Short Filenames。命令提示符不能处理超过 8 个字符的文件名,因此我们需要一种在支持引号字符串之前访问长 windows 文件名的方法。8 个字符 + 3 个用于扩展名。而且大多数系统今天仍然支持 8.3。这是一个例子。
C:\Program Files\Windows\System32\Calc.exe <- \Program Files\ is 13 characters
为了 CD 进入这个不带引号的路径,你必须使用短路径。像这样。
CD C:\Progra~1\Windows\System32\Calc.exe <-- *Progra~1 is 8 characters, 1st occurrence.*
您只需将文件或文件夹名称分解为 6 个字符,加上 ~n (n=occurrence)
如果我们有一个C:\Program Files (x86)路径,那么就像我们今天所做的那样,它将是前 6 个字符匹配的第二个路径,并且都超过了 8 个字符。
C:\Program Files becomes -> C:\Progra~1\
C:\Program Files (x86) becomes -> C:\Progra~2\
C:\MyLongFilename.txt becomes -> C:\MyLong~1\
每当我无法通过无法发送转义序列或引号的软件访问全长文件系统时,由于某种其他限制,我不得不求助于使用 8.3 短文件名来访问某些路径。在某些 Windows 机器上,引号甚至不起作用,在主机上启用它们将是一个漫长的过程。发生这种情况时,这是一个很好的解决方法。
获取短路径(通过发送到命令提示符)
C:\ for %A in ("C:\Program Files (x86)\CMake\bin\cmake.exe") do @echo %~sA
将生成 C:\Progra~1 供您使用
或者,通过将路径作为参数发送到批处理文件来获取短路径。
::getShortPath.bat
@ECHO OFF
echo %~s1
使用:-> getShortPath.bat "C:\Program Files (x86)\CMake\bin\cmake.exe"
总结一下,这里有三个示例,说明当 Windows 路径无法解析时,CMake 背后的背景可能会发生什么。
不在路径周围使用引号
使用引号有效。但有时如果 stdio >> 运行多个进程,您可能会丢失引号。在这种情况下,您需要将它们作为转义序列发送"\"C:/Program Files (x86)/CMake/bin/cmake.exe\""
4. 路径和命令行参数需要是相互独立的变量或实例。
从 CMake 发送参数时,您确实希望它们是与路径变量分开的变量。Set(CMAKE_EXE "C:\Program Files (x86)\CMake\bin\cmake.exe --version") 将不起作用。只有带有空格的路径和参数需要用引号括起来。
set(CMAKE_EXE "C:\Program Files (x86)\CMake\bin\cmake.exe" --version --trace "C:\My Soure Dir")
把它们放在一起
如果有人像我过去一样遇到 Windows/CMake 路径问题,请彻底研究这段代码,直到你完全理解它。所有报价位置。当您了解引用的内容和未引用的内容以及原因时,从长远来看应该会有很大帮助。
set(CMAKE_EXE "C:\Program Files (x86)\CMake\cmake.exe" CACHE INTERNAL "") <- make it a global variable.
set(ARGUMENTS --version --trace)
set(MyStringWithQuotesIncluded "\"This String wants it's quotes included\"")
set(MyCMakeLists "C:\MyApp\ProjectDirectory")
set(BuildHere "C:\MyBuilds\MyOSProject\bin")
set(FULL_COMMAND "${CMAKE_EXE}" ${ARGUMENTS} -DSTRING_VARIABLE="${MyStringWithQuotesIncluded}" -S "${MyCMakeLists}" -B "${BuildHere}")
execute_command(COMMAND cmd /c ${FULL_COMMAND} WORKING_DIRECTORY "${BuildHere}")
当我刚开始时,我遇到了很多通过 CMake 层处理 Windows 路径的问题。我希望这可以帮助某人在将来避免所有这些。