当从包含反斜杠的响应 @file 中读取参数时,为什么 ld 不能从 MSYS 调用找到(现有静态)库?

Why can't ld called from MSYS find (existing static) library when arguments are read from a response @file containing backslashes?

这基本上与 mingw ld cannot find some library which is exist in the search path, MinGW linker can't find MPICH2 libraries - and I'm aware that there are heaps of posts on Whosebug regarding the issue of static and dynamic linking with MinGW 中的问题相同 - 但我找不到任何说明如何解决问题的信息。

我正在 MSYS2 shell (git-bash.exe) 中的 MinGW 上构建一个带有巨大链接器命令的项目,例如(通过 g++)。该过程失败,其中包括:

/z/path/to/../../../../i686-w64-mingw32/bin/ld.exe: cannot find -lssl

我将 -Wl,--verbose 添加到 g++ 链接器调用(将传递给 ld),我可以看到 -L/z/path/to/libs/openssl/lib/mingw -lssl:

...
attempt to open /z/path/to/libs/openssl/lib/mingw/libssl.a failed
...
/z/path/to/libs/openssl/lib/mingw/ssl.dll failed
attempt to open /z/path/to/libs/openssl/lib/mingw\libssl.a failed
...

但这很奇怪,因为文件存在?

$ file /z/path/to/libs/openssl/lib/mingw/libssl.a
/z/path/to/libs/openssl/lib/mingw/libssl.a: current ar archive

(...并且它是在同一台机器上使用相同的编译器构建的)?

奇怪的是,一旦它尝试使用正斜杠 .../libssl.a 打开,一次使用反斜杠 ...\libssl.a - 但至少第一个路径在 bash shell 中检出, 如上图?

如果我尝试指定 -l:libssl.a - 或者如果我指定 -L/z/path/to/libs/openssl/lib/mingw -Wl,-Bstatic -lssl - 则会变得更糟;那么所有打开的尝试都带有反斜杠:

...
attempt to open /z/path/to/scripts/other/build/openssl/build/mingw/lib\libssl.a failed
attempt to open /z/path/to/libs/openssl/lib/mingw\libssl.a failed
...

最重要的是,如果我使用 ld 通过命令行手动查找它,它会找到 ?!:

$ ld -L/z/path/to/libs/openssl/lib/mingw -lssl --verbose
attempt to open Z:/path/to/libs/openssl/lib/mingw/libssl.dll.a failed
attempt to open Z:/path/to/libs/openssl/lib/mingw/ssl.dll.a failed
attempt to open Z:/path/to/libs/openssl/lib/mingw/libssl.a succeeded

有谁知道为什么会这样,我怎样才能 ld 最终找到这些库?或者更确切地说 - 当这些库存在于 ld 试图打开它们的路径时,我如何排除故障并理解为什么找不到这些库?


好的,发现了更多东西 - 不确定这是否是一个错误;但我的问题是我实际上是在从文件中读取参数(否则我会得到 g++: Argument list too long)。因此,要模拟:

$ echo " -Wl,--verbose -L/z/path/to/libs/openssl/lib/mingw -lssl -lcrypto " > tmcd3

$ g++ @tcmd3 2>&1 | grep succeeded | grep ssl                                   
# nothing

$ g++ `cat tcmd3` 2>&1 | grep succeeded | grep ssl
attempt to open Z:/path/to/libs/openssl/lib/mingw/libssl.a succeeded
attempt to open Z:/path/to/libs/openssl/lib/mingw/libcrypto.a succeeded

...事实证明,如果在命令行上输入完全相同的参数,那么静态库查找就会成功 - 但如果通过 @ 符号从文件中读取参数,那么静态库查找失败?!不幸的是,我不能在我的实际项目中使用,因为即使使用 cat,我仍然会得到 g++: Argument list too long ...那么我该如何解决这个问题?

好的,通过更多实验,我注意到:

  • -L/z/path/to/libs/openssl/lib/mingw,Unix 路径规范,往往会失败 - 而如果我们指定相同,除了以 Windows 驱动器号开头,即:
  • -LZ:/path/to/libs/openssl/lib/mingw,然后一切正常 - 也来自带有 @ at-sign 的参数文件:

$ echo " -Wl,--verbose -LZ:/path/to/libs/openssl/lib/mingw -lssl -lcrypto " > tmcd3
$ g++ @tcmd3 2>&1 | grep succeeded | grep ssl
attempt to open Z:/path/to/libs/openssl/lib/mingw/libssl.a succeeded
attempt to open Z:/path/to/libs/openssl/lib/mingw/libcrypto.a succeeded

我想,因为 shell 是 MSYS2/git-bash.exe,在 shell 和 /z/... 上输入完整的 POSIX 路径不是问题,因为 shell 会转换它们 - 但在文件中,没有任何东西可以转换它们,所以我们必须使用 Windows/MingW 约定来指定它们...

MSYS 在 shell 中使用时,将目录作为参数进行特殊处理。这翻译例如/<drive_letter>/blabla 到正确的 Windows 样式路径。这是为了适应不处理 Z: 样式目录根目录的 Unix 程序。

您在这里看到的是 MSYS 没有对从文件中读取的字符串执行此解释。仔细想想,很有道理,但亲身经历过,有时也很烦人。

长话短说:不要将 Unix 风格的路径放在带有命令参数的文件中。相反,将它们通过例如cygpath -w,适用于 MSYS2(应该是 Git for Windows 2+ 自带的 MSYS)。