I'm trying to compile some C++ code using your standard g++ compiler. However, rather than compiling from a file:
main.cpp:
#include <iostream>
int main(){
std::cout << "Hello World!\n";
return 0;
}
I would prefer to do something like
g++ ... "#include <iostream>\n int main(){ std::cout << \"Hello World!\n\"; return 0;}"
A previous post from stackoverflow showed that
echo "int main(){}" | gcc -Wall -o testbinary -xc++ -
works but I would like to know how it works and better yet, if there is a way to do this without the need to pipe the contents.
EDIT:
I'm doing run-time code generation where I need to generate a shared library and load the functions created.
I thought there would be a flag to tell the compiler "hey, I'm giving you the source code and not the file".
Thanks again for the help!
You mention generating C (or C++) code on the fly and then compiling it and
dlopen
-ing it.I'm doing the same in MELT (a domain specific language to extend GCC).
I don't see any valid reason to avoid putting the code in some (temporary) file. Writing even a million line of generated C or C++ lines is quite quick (in MELT, less than a few seconds, and most of that time is not the I/O!). Compiling that is much much slower (a few dozens of seconds at least), and the interest of generating C or C++ code is notably to take advantage of the optimizations provided by GCC (or some other compiler). Avoiding generating a file would win you just some milliseconds (you won't even be able to significantly measure the difference).
So just generate your file in some temporary
*.c
file (you could use hash or timestamp techniques to generate a unique file name), then have GCC compile it into some*.so
(perhaps byfork
-ing somemake
process, like I do in MELT), then remove that temporary file (perhaps usingatexit
).BTW, this technique is practically compatible with human interaction on current PCs. MELT has a read-eval-print-loop which generates a new C++ file of a few hundred lines, compiles and dlopen-s it, on each interaction, and it is quite usable!
Avoiding the generation of the file is painful, and the gain is absolutely negligible. You might generate it in some
tmpfs
filesystem on Linux (e.g. in/tmp/
). Most of the time would be spent by GCC compiling that file (especially if you compile with some optimization e.g.gcc -O -fPIC -shared somefile.c -o someplugin.so
). The time to write it on disk (by your program) and to read it (and even parse it, for C) by GCC is negligible. Use the -ftime-report option of GCC to understand where GCC is spending its time, it is not in parsing as soon as your pass-O
to GCC.Some versions of GCC or of other C compilers might reject stdin as input; some C compilers might want to
mmap
the C source file (e.g. by using"rm"
as mode forfopen
on Glibc). In general, compiling something which is not a*.c
file as C is non-standard, etc... So better avoid doing that, since the gain is negligible.If you don't care at all about optimization and want quick compilation of C (not C++) into very slow machine code, consider using instead tinycc (at least on 32 bits machines, on 64 bits it could be buggy) which has a library able to compile some C code inside a string.
tcc
and itslibtcc.a
is able to compile very fast (more than 10x times GCC) some C code but the performance of the produced machine code is very bad (very slow, unoptimized code).Once GCC has compiled your generated C code, you can of course
remove
the generated source code file. (and you could even also remove the.so
after havingdlopen
-ed it).BTW, you could use
clang++
to compile the generated C++ file. And you might use LLVM (and generate internal LLVM representation, without using any file) instead.See also this answer.
On Unix you can automate all process creating C/C++ programs by usage shell.
1.Create file (example run_c.sh)
2.Paste code to this file
3.Make this file as executable
Usage:
Testing environment
Inspired from http://django-notes.blogspot.com/2013/01/compiling-c-from-stdin.html and https://github.com/vgvassilev/cling
Alternatively you can say (e.g. in a shell-script):
The compiler reads from an input source - either the
stdin
or a file supplied. You need a pipe to supply something from elsewhere to the compiler. There is no other choice (and of course, some compilers may not have an option to read fromstdin
either)How about
popen("gcc -o -xc++ -
", "w");? Gives you a
FILE*` but the output goes straight into GCC.BTW, there is no point in using the
-Wall
flag. That's for human consumption. In fact,-w -Wfatal-errors
makes sense. Either it compiles or it doesn't.