[英]Build a C program from a C++ program
那么,我想做什么:基本上我想从另一个c ++程序(主程序)构建一个C / C ++程序(准备执行)。
我们来看这个例子:main.cpp
int main()
{
//do something
//there I will modify source of program which I want to build
sourceCode = ""; //maybe from a file
//then a function like this:
buildProgramFromSource(sourceCode, "program.exe");
}
我想从main.cpp生成的程序源
int main()
{
//do another thing
int value1 = value From main.cpp
int value2 = value frim main.cpp too
}
所以,我有源存储在main.cpp上,我想修改该源然后构建该程序。
我该如何实现呢?
或者,也许还有其他方法可以从主C ++程序生成.exe程序?
稍后编辑:假设环境没有安装任何编译器。 编译器应该集成在主程序中。
换句话说,我不想使用像环境一样使用编译器的system()或shellexecute等函数。
该应用程序将在Windows下使用。
一个例子非常有用。
它是特定于操作系统的 。 如果第二个(构建的)程序是独立程序或库(或第一个加载的某些代码),则情况会有所不同。
在Linux(和其他Posix系统)上,您可以生成C或C ++文件(通过使用常用的文本输出函数;我建议在内存中构建生成的C ++文件的某些AST )。 然后你可以通过分支进程运行一些C ++编译器(在简单的情况下,使用popen(3)或system(3) ,或使用低级fork(2)和execve(2)等.... )。 请参阅高级Linux编程了解更多信息
然后你可以用dlopen(3)动态加载获得的共享对象,并使用dlsym
检索一些符号(函数指针)
使用-rdynamic
编译和链接主程序,即g++ -Wall -g -rdynamic main.cc -o prog
; 需要-rdynamic
标志以使程序函数从加载的代码中可见。 声明加载函数的签名并声明全局函数指针是很有用的,例如:
typedef int somefun_t (const std::string&); somefun_t *globfun;
在运行时生成一个C ++文件genfoo.cc
,其函数由声明为extern "C"
的主程序访问。
将编译分成具有位置无关代码的共享对象( 共享库 ):从程序内部运行: g++ -Wall -fPIC -g -O -shared genfoo.cc -o genfoo.so
从你的主程序中调用dlopen
和dlsym
(请注意,如果你传递一个没有任何/
的文件名, dlopen
做一些奇怪的事情):
void* hdl = dlopen("./genfoo.so", RTLD_NOW); if (!hdl) { std::cerr << "dlopen:" << dlerror() << std::endl; exit(EXIT_FAILURE); }; globfun = dlsym(hdl, "func"); if (!globfun) { std::cerr << "dlsym func:" << dlerror() << std::endl; exit(EXIT_FAILURE); };
根据需要使用函数指针globfun
,例如
std::string s; int r = (*globfun) (s);
如果你是认真的,你应该在退出之前dlclose(hdl)
。
如果你只是想编译和运行一个不同的程序,事情要简单得多:只需像往常一样编译生成的程序( gcc -Wall -g genfoo.cc -o genprog
)并像往常一样执行它( system
, fork
+ execve
,.. ..)
如果目标系统没有任何C编译器(但也考虑tinycc ,它能够从包含字符串的C代码 - 内存及其libtcc
),你不能这样做。 你需要使用一些JIT编译库,如libjit , GNU lightning , asmjit 。 ....或者考虑嵌入一些脚本解释器,如Lua或Guile
我不知道Windows,但传闻它具有等效的动态加载功能,例如LoadLibrary 。 如果要避免在运行时运行C编译器,则还需要一些JIT库。 细节不同( dllexport
)
一些框架或库( Poco , Qt , Boost ....)正在为这些动态加载功能提供系统中立的包装器。
注意:在Linux上,你几乎可以做很多 dlopen
(数十万),参见manydl.c 。 我的MELT系统(域专用语言来扩展GCC )正在产生C ++代码和dlopen
-ing它的飞行。
另请注意,某些编程语言(如Common Lisp (以及Meta-Ocaml ))更适合运行时评估和元编程 ( 多阶段 )。 值得注意的是,它的Common Lisp的SBCL实现能够编译任意表达式,然后在运行时运行它们! 另见J.Pitrat的博客 。
最简单的解决方案可能是在程序的文件中包含一个独立的编译器。 当程序需要重新编译时:
system("copy main.cpp new_main.cpp");
在窗户上 new_main.cpp
的流(假设您的代码名为new copy new_main.cpp
) g++ new_main.cpp -o new_main.exe
system("vcvarsall");
来访问它system("vcvarsall");
(在C:\\Program Files (x86)\\Microsoft Visual Studio 11.0\\VC
找到),后跟system("cl 'path/to/project/new_main.cpp');
(在C:\\Program Files (x86)\\Microsoft Visual Studio 11.0\\VC\\bin
for me)。 在此之后你有new_main.exe
,这是main.cpp
的编译形式+一些额外的代码。
警告:如果您分发应用程序,此选项将要求您安装编译器或包含其必需的文件。 您不需要使用new_main.exe
安装/包含它们,但是您需要使用编译new_main.exe
的程序安装/包含它们。
如果要从内存编译,过程类似:
main.cpp
的流 main.cpp
读取到char缓冲区(假设main.cpp
只包含ASCII字符) main.cpp
的流 compileCode(String_Version_Of_Code_Read_From_File);
作为额外的信息,如果您需要动态修改和构建程序,通常会有更好的解决方案。 情况并非总是如此,但通常有更好的方法。
第三种选择可能是编写自己的编译器,但我会高度建议不要这样做。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.