![编译到 stdout 时 g++ 出现链接器错误](https://linux22.com/image/197005/%E7%BC%96%E8%AF%91%E5%88%B0%20stdout%20%E6%97%B6%20g%2B%2B%20%E5%87%BA%E7%8E%B0%E9%93%BE%E6%8E%A5%E5%99%A8%E9%94%99%E8%AF%AF.png)
假设我有一个名为 的 C++ 文件dummy.cpp
,我需要使用 g++ 对其进行编译,使其来自 stdin,而 g++ 将编译后的二进制文件吐出到 stdout。
如果只需要 stdin 部分,则以下命令可以解决问题:
$ g++ -x c++ -o dummy - < dummy.cpp
现在添加输出部分,据我所知,我们需要使用例如/dev/stdout
(或/proc/self/fd/1
) 作为输出参数,但是它不会工作,因为它会因链接器错误而退出。
$ g++ -x c++ -o /dev/stdout - < dummy.cpp
/usr/bin/ld: final link failed: Illegal seek
collect2: error: ld returned 1 exit status
如果我通过它将它从终端重定向到文件,g++ -x c++ -o /dev/stdout - < dummy.cpp > dummy
它将正常工作。我想问题是 stdout 不可查找,当它通过管道传输到文件中时,它会“变成”。但是为什么 ld 文件是可查找的并且可以以某种方式绕过它吗?
答案1
正如评论中提到的,这是因为链接器分阶段写入文件,然后用大小和偏移量填充标头区域中的条目。 ELF 格式在文件的早期部分包含这些值,以便轻松高效地查找适当的部分,因此链接器很自然地按照其方式工作。专为流式传输而设计的格式(例如 Zip 文件)由于将清单数据放在末尾,因此往往会变得更加复杂。
虽然理论上可以实现流输出支持,但这样做可能需要缓冲大量数据、两次计算数据或各种其他低效实践,并且由于这种情况非常罕见,因此可能不值得考虑代码复杂性以及链接器中潜在的低效率。您可能可以使用一个小的 shell 脚本,甚至一个 shell 单行代码,使用临时文件并进行适当的清理来实现此目的。