如何使用 CMake 和 NMake 查看底层 compiler/linker 命令行?
How to see the underlying compiler/linker command line with CMake & NMake?
因此默认情况下使用响应文件来指定命令行切换到某些工具链的编译器和链接器。不过,这似乎只适用于 makefile。可以说,这样做是为了绕过 Windows 上命令行的 8192 个字符长度限制,考虑到我使用 NMake Makefiles
生成器的情况。
显然,这些设置应该由 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_INCLUDES
和 CMAKE_<LANG>_USE_RESPONSE_FILE_FOR_LIBRARIES
的形式存在。
虽然这在技术上 有效 但它确实给我带来了一个不希望的副作用。在自动构建的日志中,我想看看发生了什么(是的,我也在设置 CMAKE_VERBOSE_MAKEFILE=ON
)。鉴于这些响应文件是动态生成的,我从日志文件中看到的命令行类似于:
C:\PROGRA~2\MICROS~119\PROFES~1\VC\Tools\MSVC22~1.279\bin\Hostx86\x86\cl.exe @C:\Users\XA1DB~1.RLM\AppData\Local\Temp\nm2A99.tmp
这意味着我无法再看到正在传递的参数。输出基本上对我的目的变得无用。
我怎样才能让 CMake 生成 makefile,它还会向我显示 在线响应文件的内容,以便我可以收集 compiler/linker 命令来自构建日志的行参数?
注意:不要误会我的意思,我完全理解 Windows 的现有限制。然而,即使调用编译器或链接器的实际 调用 使用响应文件,我也只是想查看响应文件内容而不是响应文件名。我正在寻找一种规范的方法来做到这一点,而不必想出一些会在下次 CMake 更新其内部结构时中断的 hacky 解决方案。
我还发现看到 2019 年使用的 8.3(替代)路径名称有点令人担忧(给定 fsutil behavior set disable8dot3 1
/ NtfsDisable8dot3NameCreation
),但也许 CMake 作者有我不知道的见解有。我无法在 Git repo.
的最新源代码中找到任何设置来配置该行为
注意: TL;DR 朝向底部。
我同时取得了一些进展,但不幸的是,乍一看应该影响所述行为的变量没有做任何事情(或者不是人们从评论中期望的方式),即使是强行为它们缓存空值。摘自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.cmake
和 Windows-Borland-CXX.cmake
是可能的继任者,他们又分别包括 Windows-Embarcadero-C.cmake
和 Windows-Embarcadero-CXX.cmake
。但是一旦我追寻到那个线索,我发现可能是对 Windows-bcc32.cmake
的第二个引用(在评论中还有另一个实际上引用了 "Borland")似乎是无关紧要的。
然而,相关的是两个变量 CMAKE_START_TEMP_FILE
和 MAKE_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_FILE
和 CMAKE_END_TEMP_FILE
在它们使用的地方已经扩展,到 project()
完成时。这意味着 改变 Windows.cmake
将是唯一(丑陋的)可行的选择......除了......
TL;DR
在调用 project()
后添加以下内容,但请注意 if/whenever 您正在命令行上处理大量 files/arguments,这很可能会影响 "ceiling" 关于 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
中收集的。我只是把它变成了一个循环以更简洁,因为我需要这样 "treat" 相当多的变量。
这样做是用空字符串替换 NMake 文件中使用的各种命令中的 CMAKE_START_TEMP_FILE
/CMAKE_END_TEMP_FILE
实例,从而禁用内联文件的特殊 NMake 语法。因为,事实证明,无法看到命令的罪魁祸首不是 CMake,而是 NMake。
现在,这开辟了多种其他可供尝试的替代方案。想法:
- 将
KEEP
附加到 CMAKE_END_TEMP_FILE
以保持响应文件在...
- 附加文件名以用于
CMAKE_START_TEMP_FILE
(参见 "reusing inline files" and this answer)。
nmake 有一个显示内联文件/响应文件的选项:
/U Dump inline files
对于递归 make,您可能希望在这样的环境变量中进行设置:
set MAKEFLAGS=U
这样,所有响应文件的内容都会出现在控制台上。
因此默认情况下使用响应文件来指定命令行切换到某些工具链的编译器和链接器。不过,这似乎只适用于 makefile。可以说,这样做是为了绕过 Windows 上命令行的 8192 个字符长度限制,考虑到我使用 NMake Makefiles
生成器的情况。
显然,这些设置应该由 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_INCLUDES
和 CMAKE_<LANG>_USE_RESPONSE_FILE_FOR_LIBRARIES
的形式存在。
虽然这在技术上 有效 但它确实给我带来了一个不希望的副作用。在自动构建的日志中,我想看看发生了什么(是的,我也在设置 CMAKE_VERBOSE_MAKEFILE=ON
)。鉴于这些响应文件是动态生成的,我从日志文件中看到的命令行类似于:
C:\PROGRA~2\MICROS~119\PROFES~1\VC\Tools\MSVC22~1.279\bin\Hostx86\x86\cl.exe @C:\Users\XA1DB~1.RLM\AppData\Local\Temp\nm2A99.tmp
这意味着我无法再看到正在传递的参数。输出基本上对我的目的变得无用。
我怎样才能让 CMake 生成 makefile,它还会向我显示 在线响应文件的内容,以便我可以收集 compiler/linker 命令来自构建日志的行参数?
注意:不要误会我的意思,我完全理解 Windows 的现有限制。然而,即使调用编译器或链接器的实际 调用 使用响应文件,我也只是想查看响应文件内容而不是响应文件名。我正在寻找一种规范的方法来做到这一点,而不必想出一些会在下次 CMake 更新其内部结构时中断的 hacky 解决方案。
我还发现看到 2019 年使用的 8.3(替代)路径名称有点令人担忧(给定 fsutil behavior set disable8dot3 1
/ NtfsDisable8dot3NameCreation
),但也许 CMake 作者有我不知道的见解有。我无法在 Git repo.
注意: TL;DR 朝向底部。
我同时取得了一些进展,但不幸的是,乍一看应该影响所述行为的变量没有做任何事情(或者不是人们从评论中期望的方式),即使是强行为它们缓存空值。摘自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.cmake
和 Windows-Borland-CXX.cmake
是可能的继任者,他们又分别包括 Windows-Embarcadero-C.cmake
和 Windows-Embarcadero-CXX.cmake
。但是一旦我追寻到那个线索,我发现可能是对 Windows-bcc32.cmake
的第二个引用(在评论中还有另一个实际上引用了 "Borland")似乎是无关紧要的。
然而,相关的是两个变量 CMAKE_START_TEMP_FILE
和 MAKE_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_FILE
和 CMAKE_END_TEMP_FILE
在它们使用的地方已经扩展,到 project()
完成时。这意味着 改变 Windows.cmake
将是唯一(丑陋的)可行的选择......除了......
TL;DR
在调用 project()
后添加以下内容,但请注意 if/whenever 您正在命令行上处理大量 files/arguments,这很可能会影响 "ceiling" 关于 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
中收集的。我只是把它变成了一个循环以更简洁,因为我需要这样 "treat" 相当多的变量。
这样做是用空字符串替换 NMake 文件中使用的各种命令中的 CMAKE_START_TEMP_FILE
/CMAKE_END_TEMP_FILE
实例,从而禁用内联文件的特殊 NMake 语法。因为,事实证明,无法看到命令的罪魁祸首不是 CMake,而是 NMake。
现在,这开辟了多种其他可供尝试的替代方案。想法:
- 将
KEEP
附加到CMAKE_END_TEMP_FILE
以保持响应文件在... - 附加文件名以用于
CMAKE_START_TEMP_FILE
(参见 "reusing inline files" and this answer)。
nmake 有一个显示内联文件/响应文件的选项:
/U Dump inline files
对于递归 make,您可能希望在这样的环境变量中进行设置:
set MAKEFLAGS=U
这样,所有响应文件的内容都会出现在控制台上。