【问题标题】:How to see the underlying compiler/linker command line with CMake & NMake?如何使用 CMake 和 NMake 查看底层编译器/链接器命令行?
【发布时间】:2019-08-05 11:51:30
【问题描述】:

因此默认情况下使用响应文件来为某些工具链指定编译器和链接器的命令行开关。不过,这似乎只适用于 makefile。考虑到我使用 NMake Makefiles 生成器的场景,可以说这样做是为了绕过 Windows 上命令行的 8192 个字符长度限制。

显然,这些设置应该由CMAKE_<LANG>_USE_RESPONSE_FILE_FOR_OBJECTS 管理,据我所知,它并没有完全记录在案。无论如何,CMake (3.15.1) 发行版附带的各种 CMake 脚本包含这些设置的 0 或 1(即每种语言 <LANG>)。唯一似乎被阅读的地方是cmMakefileTargetGenerator.cxx 中的cmMakefileTargetGenerator::CheckUseResponseFileForObjects()(在撰写本文时)。

补充设置以CMAKE_<LANG>_USE_RESPONSE_FILE_FOR_INCLUDESCMAKE_<LANG>_USE_RESPONSE_FILE_FOR_LIBRARIES的形式存在。

现在,虽然这在技术上有效,但它确实给我带来了一个不受欢迎的副作用。在自动构建的日志中,我想看看发生了什么(是的,我也在设置CMAKE_VERBOSE_MAKEFILE=ON)。鉴于这些响应文件是动态生成的,我从日志文件中看到的命令行类似于:

C:\PROGRA~2\MICROS~1\2019\PROFES~1\VC\Tools\MSVC\1422~1.279\bin\Hostx86\x86\cl.exe @C:\Users\XA1DB~1.RLM\AppData\Local\Temp\nm2A99.tmp

这意味着我不再能看到正在传递的参数。对于我的目的,输出基本上变得毫无用处。

如何让 CMake 生成生成文件,该文件还会向我显示内联响应文件的内容,以便我可以从构建日志中收集编译器/链接器命令行参数?

注意:不要误会我的意思,我完全理解 Windows 上的现有限制。但是,即使调用编译器或链接器的实际 call 使用响应文件,我也只想查看响应文件内容而不是响应文件名。我正在寻找一种规范的方式来做到这一点,而不必想出一些在下次 CMake 对其内部进行更新时会破坏的 hacky 解决方案。


我还发现看到 2019 年使用的 8.3(替代)路径名称有点令人担忧(给定 fsutil behavior set disable8dot3 1 / NtfsDisable8dot3NameCreation),但也许 CMake 作者有我没有的见解。我在Git repo 的最新源代码中找不到任何设置来配置该行为。

【问题讨论】:

    标签: visual-c++ cmake nmake


    【解决方案1】:

    nmake 有一个显示内联文件/响应文件的选项:

    /U 转储内联文件

    对于递归 make,您可能希望在这样的环境变量中设置它:

    set MAKEFLAGS=U
    

    这样,所有响应文件的内容都会出现在控制台上。

    【讨论】:

    • 按照我在问答中奖励他人在我自己回答的问题中提供的任何有用答案的传统,我接受您的回答。
    【解决方案2】:

    注意: TL;DR 朝向底部。

    我同时取得了一些进展,但不幸的是,乍一看应该影响所述行为的变量并没有做任何事情(或者不是人们对 cme​​ts 的期望),即使在强制缓存为空时也是如此他们的价值观。摘自Modules\Platform\Windows.cmake

    # for nmake make long command lines are redirected to a file
    # with the following syntax, see Windows-bcc32.cmake for use
    if(CMAKE_GENERATOR MATCHES "NMake")
      set(CMAKE_START_TEMP_FILE "@<<\n")
      set(CMAKE_END_TEMP_FILE "\n<<")
    endif()
    
    include(Platform/WindowsPaths)
    
    # uncomment these out to debug nmake and borland makefiles
    #set(CMAKE_START_TEMP_FILE "")
    #set(CMAKE_END_TEMP_FILE "")
    #set(CMAKE_VERBOSE_MAKEFILE 1)
    

    我找不到注释中引用的Windows-bcc32.cmake,但可以理解为它指的是 Borland C 编译器可执行文件的旧名称。所以Windows-Borland-C.cmakeWindows-Borland-CXX.cmake 是可能的继任者,他们又分别包括Windows-Embarcadero-C.cmakeWindows-Embarcadero-CXX.cmake。但是,一旦我追查到这条线索,我发现可能第二次引用 Windows-bcc32.cmake(评论中还有另一个实际上引用了“Borland”)似乎无关紧要。

    但是,相关的是CMAKE_START_TEMP_FILEMAKE_END_TEMP_FILE 这两个变量。但是,在调用 project() 之后设置它们(甚至强制写入缓存)并不会产生预期的效果。

    这些变量在Windows.cmake(上面摘录)中定义,使用在:

    • Modules\Platform\Windows-df.cmake
    • Modules\Platform\Windows-Embarcadero.cmake
    • Modules\Platform\Windows-MSVC.cmake
    • Modules\Platform\Windows-NVIDIA-CUDA.cmake
    • Modules\Platform\Windows-OpenWatcom.cmake
    • Modules\Platform\Windows-PGI.cmake
    • Tests\RunCMake\add_link_options\LINKER_expansion-list.cmake
    • Tests\RunCMake\Make\VerboseBuild.cmake
    • Tests\RunCMake\target_link_options\LINKER_expansion.cmake
    • Source\cmMakefileTargetGenerator.cxx

    CMAKE_START_TEMP_FILECMAKE_END_TEMP_FILE 似乎已经在它们使用的地方进行了扩展,直到 project() 完成。这意味着更改Windows.cmake 将是唯一(丑陋)可行的选择......除了......

    TL;DR

    在调用project() 之后添加以下内容,但请注意,如果/每当您在命令行上处理大量文件/参数时,这很可能会达到命令行的“上限” Windows 上的长度限制。但这就是让 NMake 执行的命令再次可见的方法。

    set(CMAKE_CXX_USE_RESPONSE_FILE_FOR_INCLUDES 0 FORCE)
    foreach(lang IN ITEMS C CXX)
        foreach(cmd IN ITEMS COMPILE_OBJECT CREATE_SHARED_LIBRARY CREATE_PREPROCESSED_SOURCE CREATE_ASSEMBLY_SOURCE LINK_EXECUTABLE)
            string(REPLACE "${CMAKE_START_TEMP_FILE}" "" CMAKE_${lang}_${cmd} "${CMAKE_${lang}_${cmd}}")
            string(REPLACE "${CMAKE_END_TEMP_FILE}" "" CMAKE_${lang}_${cmd} "${CMAKE_${lang}_${cmd}}")
        endforeach()
    endforeach()
    

    顺便说一句:顺便说一句,替换语法是从Tests\RunCMake\Make\VerboseBuild.cmake 收集的。我只是把它做成一个更简洁的循环,因为我需要以这种方式“处理”很多变量。

    这样做是用空字符串替换 NMake 文件中使用的各种命令中的 CMAKE_START_TEMP_FILE/CMAKE_END_TEMP_FILE 实例,从而禁用内联文件的特殊 NMake 语法。因为,事实证明,无法看到命令的罪魁祸首不是 CMake,而是 NMake。

    参考:Inline Files in a Makefile

    现在,这开辟了人们可以尝试的各种其他替代方案。想法:

    • KEEP 附加到CMAKE_END_TEMP_FILE 以保留响应文件...
    • 将要使用的文件名附加到CMAKE_START_TEMP_FILE(请参阅"reusing inline files"this answer)。

    【讨论】:

      猜你喜欢
      • 2012-08-26
      • 1970-01-01
      • 2011-03-23
      • 2014-07-21
      • 1970-01-01
      • 2015-09-29
      • 1970-01-01
      • 2020-11-11
      • 2018-05-14
      相关资源
      最近更新 更多