如何将目标文件通过管道传输到 GCC 中进行链接?

如何将目标文件通过管道传输到 GCC 中进行链接?

我的玩具语言自定义编译器使用 Cranelift 生成目标代码,我可以将其写入文件中main.o。为了使该目标文件成为可执行文件,我使用gcc -o main main.o.

但是,我想将代码直接通过管道传输到 GCC 中,以免将临时目标文件写入磁盘,因此我让编译器将目标代码写入标准输出。用作-文件名不起作用,因为该-x选项似乎没有任何目标文件值。

使用某种 shell 重定向也不起作用:gcc -o main <(compiler)错误与/usr/bin/ld: /proc/self/fd/11: file not recognized: Illegal seek. (请注意,当 GCC 本身处理文件时,这确实有效,例如使用gcc -xc <(echo "int main(){}") -o main,但当文件传递给 LD 时则无效。该-pipe选项似乎也没有什么区别。)

有什么方法可以使用 GCC 来链接通过管道传输到其中的目标代码吗?

答案1

ld需要一个可查找的文件,所以你不能使用管道。 Korn <(...)shell 进程替换扩展到管道的路径。

您需要 zsh 及其之一或=(...)Fish 及其来获取常规可查找文件(在后台(...|psub -f)创建)的路径。$TMPPREFIX$TMPDIR

gcc -o main =(compiler) # zsh
gcc -o main (compiler|psub -f) # fish

如果ld需要文件的路径以.o, in结尾zsh,则设置TMPSUFFIX=.o.

在其他 shell 中,您可以手动创建临时文件,您甚至可以调用gcc它,甚至可以compiler在删除它后将其输出重定向到它。在类似 Korn/POSIX 的 shell 中:

file=$(mktemp) && {
  rm -f -- "$file" &&
    compiler >&3 3>&- 4<&- &&
    gcc -o main /dev/fd/4 3>&-
} 3> "$file" 4<> "$file"

请注意,gcc它本身会为自己的处理创建许多临时文件,因此尝试避免在这里创建额外的临时文件是没有意义的。

答案2

你不能管道编译器的目标文件。正如错误所示,这不起作用,因为 gcc 试图在其中查找,而这不是管道支持的操作。 (它适用于源代码只是因为 gcc 是用特定的词法/解析编写的,这似乎确实按顺序消耗输入。)

所以,必须有一个匿名临时文件!

 gcc -o main =(yourcompiler)

会解决你的问题:

如果使用 =(...) 而不是 <(...),则作为参数传递的文件将是包含列表进程输出的临时文件的名称。对于希望在输入文件上进行 lseek(请参阅 lseek(2))的程序,可以使用它来代替 < 形式。

但是:这只是 zsh 的一个功能,而不是更常见的 bash,所以我不知道您是否想使用它,或者只是便携式写入目标文件并链接它 - 就像任何拥有 makefile 或 ninja 脚本的人一样,或者一个发电机就可以了。

另请注意,如果您的编译器采用中间代码作为输入,也许您实际上想将其更改为 llvm 后端?这样,您可以将其作为插件加载到 clang 中,然后直接将源代码编译为目标文件,甚至可以立即进行组合的链接和编译运行。

相关内容