rustc如何从bash进程替代中编译源代码,但gcc无法编译源代码?

汤玛斯·雅尼克
$ rustc <(echo 'fn main(){ print!("Hello world!");}')
$ ls
63
$ gcc <(echo '#include<stdio.h> int main(){ printf("Hello world!\n"); return 0;}')
/dev/fd/63: file not recognized: Illegal seek
collect2: error: ld returned 1 exit status

为什么不能ld链接程序?

gcc命令主要是调度引擎。对于每个输入文件,它根据文件名的扩展名确定文件的类型,然后将文件传递给适当的处理器。因此,.c文件由C编译器编译,.h文件被组装为预编译的头文件,.go文件被发送到cgo编译器,依此类推。

如果文件名没有扩展名或无法识别扩展名,则gcc假定它是某种对象文件,应参与最后的链接步骤。这些文件被传递到collect2实用程序,然后实用程序ld可能调用两次。进程替换就是这种情况,它产生的文件名如/dev/fd/63,不包括扩展名。

ld不依赖文件名来标识目标文件格式。它通常由几个不同的目标文件识别器构建,每个目标文件识别器都取决于某种“魔数”(即,文件开头或附近的特殊模式)。它一次将这些识别器调用一次,直到找到一个乐于解释该文件的识别器。如果该文件未被识别为二​​进制格式,则ld假定它是一个链接描述文件(这是一个纯文本文件),并尝试将其解析为此类文件。

自然,两次尝试之间ld需要倒回文件,并且由于进程替换会安排传递管道而不是文件,因此查找将失败。(如果您尝试将文件通过stdin重定向传递到管道,则会发生相同的事情,您可以这样做:stdin如果将gcc指定-为文件名,gcc将作为文件处理。但是它坚持要求您告诉它哪种文件是的,请参见下文。)

由于ld无法倒带文件,因此在文件与第一次猜测不符之后它将失败。因此,来自的错误消息ld有点误导,因为您可能认为该文件已被编译,并且随后的失败在链接步骤中。事实并非如此;因为文件名没有扩展名,所以gcc直接跳到链接阶段,几乎立即失败。

在使用进程替换,管道,stdin和命名错误的文件的情况下,您仍然可以手动确定gcc文件是什么。您可以使用该-x选项来完成此操作,该选项在GCC手册部分中介绍了控制输出类型的选项(尽管在这种情况下,该选项实际上控制了输入的类型)。

诸如此类的问题在Internet上有很多答案,其中包括StackOverflow上的各种答案,这些答案声称GCC试图检测输入文件的语言。它不会这样做,而且永远不会。(而且我怀疑它是否会成功,因为它所编译的某些语言彼此非常相似,以致不可能进行精确检测。)进行自动检测的唯一组件是ld,并且只有在GCC做出不可撤消的决定后,它才会这样做。将输入文件视为目标文件或链接描述文件。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章