您提到即时生成 C(或 C++)代码,然后对其进行编译和dlopen
-ing。
我在MELT(一种扩展 GCC 的领域特定语言)中做同样的事情。
我没有看到任何避免将代码放入某个(临时)文件的正当理由。甚至编写一百万行生成的 C 或 C++ 行都非常快(在 MELT 中,不到几秒钟,而且大部分时间都不是 I/O!)。编译要慢得多(至少几十秒),生成 C 或 C++ 代码的兴趣主要是利用 GCC(或其他一些编译器)提供的优化。避免生成文件只会为您赢得几毫秒(您甚至无法显着衡量差异)。
所以只需在一些临时*.c
文件中生成你的文件(你可以使用哈希或时间戳技术来生成一个唯一的文件名),然后让 GCC 将它编译成一些文件*.so
(也许通过fork
-ing 一些make
过程,就像我在 MELT 中所做的那样),然后删除它临时文件(可能使用atexit
)。
顺便说一句,这种技术实际上与当前 PC 上的人机交互兼容。MELT 有一个 read-eval-print-loop,它生成一个几百行的新 C++ 文件,在每次交互时编译和 dlopen-s 它,它非常有用!
避免文件的生成是痛苦的,收益绝对可以忽略不计。tmpfs
您可能会在 Linux 上的某些文件系统中生成它(例如 in /tmp/
)。大部分时间将花在 GCC 编译该文件上(特别是如果您使用一些优化进行编译,例如gcc -O -fPIC -shared somefile.c -o someplugin.so
)。GCC 将它写入磁盘(通过您的程序)和读取它(甚至解析它,对于 C)的时间可以忽略不计。使用 GCC 的-ftime-report选项来了解 GCC 将时间花在哪里,它不会在您传递-O
给 GCC 后立即进行解析。
某些版本的 GCC 或其他 C 编译器可能拒绝stdin作为输入;一些 C 编译器可能想要mmap
C 源文件(例如,通过在 Glibc 上使用"rm"
as 模式)。fopen
通常,将不是*.c
文件的东西编译为C是非标准的,等等......所以最好避免这样做,因为增益可以忽略不计。
如果您根本不关心优化并希望将 C(不是 C++)快速编译成非常慢的机器代码,请考虑使用具有库的tinycc(至少在 32 位机器上,在 64 位机器上可能有问题)能够在字符串中编译一些 C 代码。tcc
它libtcc.a
能够非常快地编译一些 C 代码(超过 GCC 的 10 倍),但生成的机器代码的性能非常差(非常慢,未优化的代码)。
一旦 GCC 编译了您生成的 C 代码,您当然可以remove
生成生成的源代码文件。(你甚至可以在-ed.so
之后删除它)。dlopen
顺便说一句,您可以clang++
用来编译生成的 C++ 文件。您可能会使用 LLVM(并生成内部 LLVM 表示,而不使用任何文件)。
另请参阅此答案。
我正在生成运行时代码,我需要生成一个共享库并加载创建的函数。
还可以考虑使用JIT 编译库,例如libgccjit、LLVM或asmjit。还可以查看SBCL(几乎在每次REPL交互时都会生成机器代码)。当然,您需要了解系统上的相关调用约定和ABI。所以还要阅读这个,elf(5)和 Drepper 的论文如何编写共享库