如何通过 MSVS 2017 x64 命令行将链接器选项传递给 `cl`?

3
我有一个小程序,我想通过命令行执行它。我从IDE中运行它,它可以正常运行。我复制整个编译命令并将其粘贴到MSVS命令提示符中,然后我会得到未解析的符号链接错误(我之前在一些不需要传递链接器选项的程序上做过这样的事情)。
我从文档中读到需要指定 /link linker-options(从此处)。但是当我这样做时,我会遇到其他错误。然后按照指示我去了这里,应该告诉我如何指定链接器选项。但是它没有,它只是一个针对link.exe的参考资料。我需要将cl命令传输到link.exe中吗?我需要在cl之后执行它吗?我也找不到例子。
只是为了测试,以下是简单的程序main.cpp:
#include <iostream>
#include <Windows.h>
#include <string>

int main()
{
    DWORD pid;
    HWND hwnd = FindWindow(0, L"Calculator");
    GetWindowThreadProcessId(hwnd, &pid);
    if (hwnd) {
        std::cout << "Window is open, id = " << pid;
    }
    else {
        std::cout << "Window not found" << '\n';
    }
    system("Pause");
}

在IDE中,它可以正常工作。现在,我将完整的命令从MSVS 2017编译器部分复制如下:/JMC /permissive- /we"4239" /GS /Zc:rvalueCast /W3 /Zc:wchar_t /ZI /Gm- /Od /Fd"x64\Debug\vc141.pdb" /Zc:inline /fp:precise /D "_DEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /MDd /std:c++17 /FC /Fa"x64\Debug\" /EHsc /nologo /Fo"x64\Debug\" /Fp"x64\Debug\GetProcessByName.pch" /diagnostics:classic

连接器部分为:/OUT:"J:\nik\Documents\Visual_Studio_Projects\GetProcess\x64\Debug\GetProcessByName.exe" /MANIFEST /NXCOMPAT /PDB:"J:\nik\Documents\Visual_Studio_Projects\GetProcess\x64\Debug\GetProcessByName.pdb" /DYNAMICBASE "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" /DEBUG /MACHINE:X64 /INCREMENTAL /PGD:"J:\nik\Documents\Visual_Studio_Projects\GetProcess\x64\Debug\GetProcessByName.pgd" /SUBSYSTEM:CONSOLE /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /ManifestFile:"x64\Debug\GetProcessByName.exe.intermediate.manifest" /ERRORREPORT:PROMPT /NOLOGO /TLBID:1

如Mike所说,我将它们组合在一起:cl [compile-options] main.cpp /link [linker-options],并在main.cpp所在的目录中执行此命令。

输出结果为:c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.1 5.26726\include\xlocale(319): warning C4530: C++ exception handler used, but unw ind semantics are not enabled. Specify /EHsc C:\Users\nik\documents\Visual_Studio_Projects\GetProcess\GetProcessByName\m ain.cpp : fatal error C1083: Cannot open compiler generated file: 'x64\Debug" /E Hsc /nologo /Fox64\Debug".asm': Invalid argument

如何正确“传递”/指定链接器选项以从命令行构建程序并运行它?

cl [compile-options] /link [linker-options] 是正确的。cl [compile-options] 后跟 link [linker-options] 也可以。显然,您在获取 [linker-options] 方面出现了问题,但要获得帮助,您需要编辑您的帖子以向我们展示失败的命令行及其随后的错误,逐字逐句。 - Mike Kinghan
@MikeKinghan 感谢您的帮助。我已经更新了问题。 - KeyC0de
1个回答

2
你看到的错误是编译选项中的Shell解析错误。因此,该命令实际上没有进行编译,更不用说链接了。如果确实会出现任何链接选项引起的问题,那么这个问题并没有向我们展示它们是什么。
我们看到的解析错误是由选项引起的:
/Fa"x64\Debug\"

/Fa的文档规定,当使用以下格式时:

/Fa directory\

用于指定汇编清单输出目录的选项为 -L,在使用时必须包含结尾的 \,以区分该选项与其他选项的不同:

/Fa filename

您已经完成了这个步骤,并且使用引号将目录名括起来 - "x64\Debug\"

当您正在执行命令的 Windows shell (cmd) 解析命令行时,它会将引号 "..." 内的 \ 视为一个转义字符。

因此,结尾处的 \ 转义了 "x64\Debug\" 中的结束引号 ",并且 /Fadirectory\ 参数一直传递到命令的后续选项,直到编译器最终识别出以下形式:

/Fa filename

尝试打开一个名为“assembly listing”的程序集清单,但未成功。

'x64\Debug" /E Hsc /nologo /Fox64\Debug".asm'

您可以通过以下任何方式避免此解析错误:

转义引用路径中的反斜杠

更改为:

/Fa"x64\Debug\"

to:

/Fa"x64\\Debug\\"

而对于您命令行选项中的其他路径名也同样如此。

去掉引号

更改为:

/Fa"x64\Debug\"

to:

/Fax64\Debug\

只有在路径名中存在空格时,才需要使用引号将其括起来,这样shell才会解析为一个字符串而不是两个或更多的字符串。在您的任何命令行选项的任何路径名中都没有嵌入空格,因此您可以将所有引号都删除。

使用/而不是\作为路径名分隔符

修改为:

/Fa"x64\Debug\"

to:

/Fa"x64/Debug/"

对于命令行中的其他路径名也是同样的处理方式。Windows 是唯一使用 \ 作为路径名分隔符的操作系统,其他操作系统使用 /,而 Windows 在最近的版本中也接受两种方式。

如果这会导致视觉上的混淆,即 / 用作路径分隔符 ("x64/Debug/") 和 / 用作选项前缀 (/Fa),cl 还允许您使用类 Unix 风格的选项,例如使用 -Fa 而不是 /Fa

当然,您也可以删除引号且使用 / 作为路径分隔符。

如果您只使用其中一种解决方案来修复以下解析错误:

/Fa"x64\Debug\"

然后,后续选项将会引发相同的解析错误:

/Fo"x64\Debug\"

因此,要将所选解决方案一致地应用于整个命令行。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接