2017-08-15 63 views
0

在MS Windows中cmd.exe命令行長度限制爲8192個字符。當調用接受多個文件作爲參數的工具,很容易用太長的命令行結束了,像如何在Windows上使用CMake運行超過8K符號的命令?

git update-index --assume-unchanged file1 file2 file3 ... 

做什麼,如果這是調用的CMake的add_custom_target()/add_custom_command()函數時的情況?

回答

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()