我的玩具语言自定义编译器使用 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 中,然后直接将源代码编译为目标文件,甚至可以立即进行组合的链接和编译运行。