Linux 有没有办法在运行时用 C 或 C++ 编译附加代码?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10564670/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is there any way to compile additional code at runtime in C or C++?
提问by Matt
Here is what I want to do:
这是我想要做的:
- Run a program and initialize some data structures.
- Then compile additional code that can access/modify the existing data structures.
- Repeat step 2 as needed.
- 运行一个程序并初始化一些数据结构。
- 然后编译可以访问/修改现有数据结构的附加代码。
- 根据需要重复步骤 2。
I want to be able to do this with both C
and C++
using gcc
(and eventually Java
) on Unix-like systems (especially Linux and Mac OS X). The idea is to basically implement a read-eval-print loop for these languages that compiles expressions and statements as they are entered and uses them to modify existing data structures (something that is done all the time in scripting languages). I am writing this tool in python
, which generates the C
/C++
files, but this should not be relevant.
我希望能够既要做到这一点C
,并C++
使用gcc
(并最终Java
于)类Unix系统(特别是Linux和Mac OS X)。这个想法基本上是为这些语言实现一个 read-eval-print 循环,在输入表达式和语句时编译它们,并使用它们来修改现有的数据结构(这在脚本语言中一直都在完成)。我正在编写这个工具python
,它生成C
/C++
文件,但这不应该是相关的。
I have explored doing this with shared libraries but learned that modifying shared libraries does not affect programs that are already running. I have also tried using shared memory but could not find a way to load a function onto the heap. I have also considered using assembly code but have not yet attempted to do so.
我已经探索过使用共享库执行此操作,但了解到修改共享库不会影响已在运行的程序。我也尝试过使用共享内存,但找不到将函数加载到堆上的方法。我也考虑过使用汇编代码,但还没有尝试这样做。
I would prefer not to use any compilers other than gcc
unless there is absolutely no way to do it in gcc
.
我宁愿不使用任何编译器,gcc
除非在gcc
.
If anyone has any ideas or knows how to do this, any help will be appreciated.
如果有人有任何想法或知道如何做到这一点,任何帮助将不胜感激。
采纳答案by Stephen Newell
I think you may be able to accomplish this using dynamic libraries and loading them at runtime (using dlopen
and friends).
我认为您可以使用动态库并在运行时加载它们(使用dlopen
和朋友)来完成此操作。
void * lib = dlopen("mynewcode.so", RTLD_LAZY);
if(lib) {
void (*fn)(void) = dlsym(lib, "libfunc");
if(fn) fn();
dlclose(lib);
}
You would obviously have to be compiling the new code as you go along, but if you keep replacing mynewcode.so
I think this will work for you.
您显然必须在进行过程中编译新代码,但如果您不断更换,mynewcode.so
我认为这对您有用。
回答by Matthieu M.
Even though LLVM is now used today mostly for its optimizations and backend roles in compilation, as its core it is the Low-Level Virtual Machine.
尽管 LLVM 现在主要用于其在编译中的优化和后端角色,但它的核心是低级虚拟机。
LLVM can JIT code, even though the return types may be quite opaque, so if you are ready to wrap your own code around it and don't worry too much about the casts that are going to take place, it may help you.
LLVM 可以 JIT 代码,即使返回类型可能非常不透明,因此如果您准备围绕它包装自己的代码并且不要太担心将要发生的强制转换,它可能会对您有所帮助。
However C and C++ are not really friendly for this kind of thing.
然而,C 和 C++ 对这种事情并不是很友好。
回答by Chris Stratton
If nothing else works - in particular, if un-loading a shared library ends up not being supported on your runtime platform, you could do it the hard way.
如果其他方法都不起作用 - 特别是,如果卸载共享库最终在您的运行时平台上不受支持,您可能会很困难。
1) use system() or whatever to execute gcc or make or whatever to build the code
1) 使用 system() 或其他方式执行 gcc 或 make 或其他方式来构建代码
2) either link it as a flat binary or parse whatever format (elf?) the linker outputs on your platform yourself
2)要么将它链接为一个平面二进制文件,要么自己解析你平台上的链接器输出的任何格式(elf?)
3) get yourself some executable pages, either by mmap()'ing an executable file or do doing an anonymous mmap with the execute bit set and copying/unpacking your code there (not all platforms care about that bit, but let's assume you have one that does)
3) 通过 mmap() 处理一个可执行文件或在设置了执行位的情况下执行匿名 mmap 并在那里复制/解压您的代码(并非所有平台都关心该位,但假设您有),为自己获取一些可执行页面一个这样做)
4) flush any data and instruction caches (since consistency between the two is typically not guaranteed)
4) 刷新任何数据和指令缓存(因为通常不能保证两者之间的一致性)
5) call it via a function pointer or whatever
5)通过函数指针或其他方式调用它
Of course there's another option too - depending on the level of interaction you need, you could build a separate program and either launch it and wait for the result, or fork off and launch it and talk to it by pipes or sockets. If this would meet your needs, it would be a lot less tricky.
当然还有另一种选择 - 根据您需要的交互级别,您可以构建一个单独的程序并启动它并等待结果,或者分叉并启动它并通过管道或套接字与它对话。如果这能满足您的需求,那就不那么棘手了。
回答by kravemir
There is one simple solution:
有一个简单的解决方案:
- create own library having special functions
- load created library
- execute functions from that library, pass structures as function variables
- 创建自己的具有特殊功能的库
- 加载创建的库
- 执行该库中的函数,将结构作为函数变量传递
To use your structures you have to include same header files like in host application.
要使用您的结构,您必须像在主机应用程序中一样包含相同的头文件。
structs.h:
结构体.h:
struct S {
int a,b;
};
main.cpp:
主.cpp:
#include <iostream>
#include <fstream>
#include <dlfcn.h>
#include <stdlib.h>
#include "structs.h"
using namespace std;
int main ( int argc, char **argv ) {
// create own program
ofstream f ( "tmp.cpp" );
f << "#include<stdlib.h>\n#include \"structs.h\"\n extern \"C\" void F(S &s) { s.a += s.a; s.b *= s.b; }\n";
f.close();
// create library
system ( "/usr/bin/gcc -shared tmp.cpp -o libtmp.so" );
// load library
void * fLib = dlopen ( "./libtmp.so", RTLD_LAZY );
if ( !fLib ) {
cerr << "Cannot open library: " << dlerror() << '\n';
}
if ( fLib ) {
int ( *fn ) ( S & ) = dlsym ( fLib, "F" );
if ( fn ) {
for(int i=0;i<11;i++) {
S s;
s.a = i;
s.b = i;
// use function
fn(s);
cout << s.a << " " << s.b << endl;
}
}
dlclose ( fLib );
}
return 0;
}
output:
输出:
0 0
2 1
4 4
6 9
8 16
10 25
12 36
14 49
16 64
18 81
20 100
You can also create mutable programthat will be changing itself (source code), recompiling yourself and then replace it's actual execution with execv
and save resources with shared memory.
您还可以创建将改变自身(源代码)的可变程序,重新编译自己,然后execv
用共享内存替换它的实际执行并节省资源。
回答by Doug Binks
Yes - you can do this with Runtime Compiled C++(or take a look at the RCC++ blog and videos), or one of its alternatives.
是的 - 您可以使用Runtime Compiled C++(或查看RCC++ 博客和视频)或其替代方案之一来执行此操作。
回答by Ryan Hilbert
This can be done portably with OpenCL
这可以通过 OpenCL 便携地完成
OpenCLis a widely supportedstandard, mainly used for offloading calculations to specialized hardware, such as GPUs. However, it also works just fine on CPUs and actually performs run-time compilation of C99-like code as one of its core features (this is how the hardware portability is achieved). The newer versions (2.1+) also accept a large subset of C++14.
OpenCL是一种广泛支持的标准,主要用于将计算卸载到专用硬件,例如 GPU。但是,它在 CPU 上也能正常工作,并且实际上将 C99 类代码的运行时编译作为其核心功能之一(这就是实现硬件可移植性的方式)。较新的版本 (2.1+) 也接受 C++14 的一大子集。
A basic example of such run-time compilation & execution might look something like this:
这种运行时编译和执行的基本示例可能如下所示:
#ifdef __APPLE__
#include<OpenCL/opencl.h>
#else
#include<CL/cl.h>
#endif
#include<stdlib.h>
int main(int argc,char**argv){//assumes source code strings are in argv
cl_int e = 0;//error status indicator
cl_platform_id platform = 0;
cl_device_id device = 0;
e=clGetPlatformIDs(1,&platform,0); if(e)exit(e);
e=clGetDeviceIDs(platform,CL_DEVICE_TYPE_ALL,1,&device,0); if(e)exit(e);
cl_context context = clCreateContext(0,1,&device,0,0,&e); if(e)exit(e);
cl_command_queue queue = clCreateCommandQueue(context,device,0,&e); if(e)exit(e);
//the lines below could be done in a loop, assuming you release each program & kernel
cl_program program = clCreateProgramWithSource(context,argc,(const char**)argv,0,&e);
cl_kernel kernel = 0; if(e)exit(e);
e=clBuildProgram(program,1,&device,0,0,0); if(e)exit(e);
e=clCreateKernelsInProgram(program,1,&kernel,0); if(e)exit(e);
e=clSetKernelArg(kernel,0,sizeof(int),&argc); if(e)exit(e);
e=clEnqueueTask(queue,kernel,0,0,0); if(e)exit(e);
//realistically, you'd also need some buffer operations around here to do useful work
}