在MS Windows中cmd.exe
命令行长度限制为8192个字符。当调用一个接受多个文件作为参数的工具时,很容易得到太长的命令行,比如
git update-index --assume-unchanged file1 file2 file3 ...
如果在调用CMake的add_custom_target()
/ add_custom_command()
函数时出现这种情况该怎么办?
答案 0 :(得分:2)
我们KDE在breeze-icons项目中偶然发现了这个问题。它广泛使用符号链接,在Windows上我们必须以某种方式将它们解析为真实文件。这是在ECMWinResolveSymlinks.cmake模块中完成的。
实现时我必须解决长命令行问题。我将长文件列表拆分为"列表",其中每个子列表都短于8192.由于CMake中的列表是用;
分隔的纯字符串,因此您无法轻松创建诸如"列表列表"之类的东西。我不得不使用另一个分隔符:
来区分间接级别。之后,我在每个子列表的循环中调用git
。拆分代码如下所示:
# In functions like _checkout_symlinks() the command line can become too lengthy for Windows.
# So we partition it, but in a hacky way due to CMake doesn't have list of lists.
function(_portioned_list outvar)
list(LENGTH ARGN arglen)
if(arglen EQUAL 0)
set(${outvar} "" PARENT_SCOPE)
return()
endif()
set(init)
set(tail)
math(EXPR range "${arglen} - 1")
foreach(i RANGE ${range})
list(GET ARGN ${i} v)
string(LENGTH "${init}" initlen)
string(LENGTH ${v} vlen)
math(EXPR sumlen "${initlen} + ${vlen}")
if(sumlen LESS 8192)
list(APPEND init ${v})
else()
list(APPEND tail ${v})
endif()
endforeach()
_portioned_list(tail_portioned ${tail})
string(REPLACE ";" ":" init "${init}") # Generally this is not safe, because filepath can contain ':' character. But not on Windows. Phew.
set(${outvar} ${init} ${tail_portioned} PARENT_SCOPE)
endfunction()
可以像:
一样使用file(GLOB ${dir}/* files)
_portioned_list(portioned_files ${files})
foreach(fs IN LISTS portioned_files)
# convert back to CMake list
string(REPLACE ":" ";" fs ${fs})
execute_process(COMMAND ${somecommand} ${fs}
endforeach()